Good Clean iOS Core Data Stack

Darshan Sonde
Oct 11, 2017 · 2 min read

I was writing a new iOS 10+ only core data stack and thought I will show how simple the process has become.

DataCoordinator

I really like to have a singleton to manage the core data stack. Traditionally have always called this CoreDataManager. For now lets name it DataCoordinator.

final class DataCoordinator { 
private static var coordinator: DataCoordinator?
public class func sharedInstance() -> DataCoordinator {
if coordinator == nil {
coordinator = DataCoordinator()
}
return coordinator!
}
private init() {
}
}

3 Tier Architecture

TL;DR skip to next section. this is not required anymore.

Now we needed to setup a core data stack. we need to have 2 stacks or 2 contexts.

  1. for reading and displaying data in main thread.
  2. for writing data mostly from api calls and other background processes

This is best achieved by using a 3 tier architecture.

P1 is used to save to persistent store.

C1, C2 are child contexts of P1.

C2 is used to write from API’s. so that saved changes are propagated to C1 fast.

C1 changes are propagated to P1. as its a child context. the propagation is quick and as writing to persistent store happens in another context. operations in C1 is fairly fast. which is the whole goal of setting up the 3 tier architecture. performance!

All this is not required to be setup anymore.

NSPersistentContainer

iOS 10 has introduce a new class which reduced all the boilerplate code of setting up a 3 tier architecture to couple of lines below.

...public var container : NSPersistentContainer
private init() {
container = NSPersistentContainer(name: "Model")
container.loadPersistentStores(completionHandler:{(_, error) in
if let error = error {
fatalError("Unresolved error \(error)")
}
})
}
...

That’s it.

Container provides two ways to read and write.

  1. viewContext property
  2. performBackgroundTask method

Let’s add couple of convenience methods to help in reading and writing from container.

static func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
DataCoordinator.sharedInstance().container.performBackgroundTask(block)
}

static func performViewTask(_ block: @escaping (NSManagedObjectContext) -> Void) { block(DataCoordinator.sharedInstance().container.viewContext)
}

Reading

To read all we have to do is

DataCoordinator.performViewTask { (context) in
}

make sure to use or before using this method when working from threads.

DispatchQueue.main.async {
DataCoordinator.performViewTask { (context) in
}
}

Writing

To write all we have to do is

DataCoordinator.performBackgroundTask { (context) in
}

You can find the entire code below.

Y Media Labs Innovation

Engineering blog showcasing some innovation and creativity

Darshan Sonde

Written by

Director of Technology, Head of Innovation @ymedialabs

Y Media Labs Innovation

Engineering blog showcasing some innovation and creativity

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade