The One About Containers

I had dusted off an old project where the Core Data stack was implemented using the main and private contexts, the old fashioned way, that happen to work and it worked pretty well.

However, the code… Oh.My.God. The code! Of course, my first reaction was denial, but the reality quickly set in and I took a deep breath. Then decided that instead of trying to fix the code, I will go the simpler route and drop it like it’s hot.

Also because I had updated the deployment target for the project to iOS 11, that offered a chance to use the new shiny, the NSPersistentContainer that was introduced with iOS 10.

New Way, Old Trappings

The design of NSPersistentContainer isn’t all that different from the existing ways of setting up the Core Data stack. In fact, under-the-hood it is still doing pretty much the same as the previously available methods, albeit in a much more abstracted way1. However, this abstracts the whole process of setting up the Core Data stack making it easier for the new comers (and old hands) to use Core Data in their applications.

Of course this does come with a downside, at least for the new comers, they often won’t dig deeper to understand how this works and thus will not be able to fully understand how Core Data does what it does. So the new comers may want to spend some time understanding Core Data, even if they don’t plan on manually configuring it.


The Apple document describes it as:

NSPersistentContainer simplifies the creation and management of the Core Data stack by handling the creation of the managed object model (NSManagedObjectModel), persistent store coordinator (NSPersistentStoreCoordinator), and the managed object context (NSManagedObjectContext).

What that means is that once you initialize the NSPersistentContainer object, you have a fully functional Core Data stack with main and private contexts; and that is wonderful.

In addition, the NSPersistentContainer also offers a function that let’s the user offload expensive tasks to the private context without blocking the UI. That function is called performBackgroundTask that takes a single parameter which is a block (or closure in Swift), (NSManagedObjectContext) -> Void). Calling this function, will create a new private queue context that can be used for long running and/or complex tasks without blocking the main thread.

The persistent container could still be configured to use the options for the NSPersistentStoreCoordinator, like the migration, model, and store location, among other, options; but it has some sane defaults if you don’t specify any options.

The Usage

Getting up and running using NSPersistentContainer is very easy and is a two step process:

let dataStoreContainer = NSPersistentContainer(name: "nameOfYourDataModel")

{ (storeDescription, error) in
    guard error == nil
        fatalError("Failed to load persistent store: \(String(describing: error))")

    print("Data Store: \(storeDescription)")

In the above, the first thing we do is create and instance of the NSPersistentContainer passing it the name of our data model.

Once we have an instance, we invoke the asynchronous loadPersistentStores method to load the persistent stores passing it a completion handler.

Now this part is bit interesting, because in a real application, some thought will need to put into what do we do in the completion handler and how do we react to failures. There are many ways, and all of them out of scope for this article2.

So for the the happy and simple path, when the error is nil, our persistent stores have been loaded and we can now access the main context by calling viewContext property (read-only) of the dataStoreContainer.

If we wanted a private managed object context, we can invoke the newBackgroundContext() method of the dataStoreContainer.

That is it. We have a Core Data stack up and running with both main and private contexts.



I’m not implying that I have intimate knowledge of the internal workings of NSPersistentContainer. I do not. My understanding is based on what is available as documentation for it, the header file, and what can be gleaned from how it behaves and the functionality it is offering.


Perhaps another article, another time to show at least one way of doing it. ;)