Building The Perfect Core Data Stack

Bring Your Own

Building The Perfect Core Data Stack

In this series, we are going to explore several techniques and best practices for building a robust, modern Core Data stack. Modern? Yes. Core Data has undergone several important changes in the past few years. In this series, we discuss what a modern Core Data stack looks like.

The tips, tricks, and best practices discussed in this series are proven recipes for building a robust Core Data application. But I didn't come up with these on my own. Over the years, I have learned a lot from what Apple teaches developers at WWDC and I also picked up many insights from several veteran Core Data developers, such as Marcus Zara.

Persistent Containers

I recently wrote about the new Core Data template that ships with Xcode 8. The template makes use of the brand new NSPersistentContainer class, which is available in iOS 10+, tvOS 10+, macOS 10.12+, and watchOS 3+.

This series focuses on a Core Data stack without the NSPersistentContainer class. While I love the addition of the NSPersistentContainer class, I strongly believe a proper understanding of the anatomy of a Core Data stack is instrumental to work with Core Dat. That is what this series is about.

Bring Your Own

I am sure you know about the Use Core Data checkbox Xcode provides during project setup. And you probably know a library or two that helps you with Core Data. But how do you create a Core Data stack from scratch? How do you make sure you can safely access managed objects from different threads? How do you make sure the user interface doesn't freeze when you save changes to disk?

These questions, and many more, get a proper answer in this series. In the first installment of this series, we start by taking a look at some improvements we can make to the default Core Data stack Xcode gives us when we check Use Core Data.

Why Bring Your Own

If you are building an application that makes use of Core Data, I urge you to leave the checkbox Use Core Data unchecked when setting up your project. Having Xcode create a Core Data stack for you is fine if you are learning the framework or if you quickly want to try something out. Even though Xcode tries to be helpful by adding a basic Core Data stack in the application delegate, there are several good arguments for setting up your own Core Data stack.

While I appreciate that Apple makes it easy to get started with Core Data, in the end, it doesn't help anyone. There are a number of issues with the Core Data stack Xcode creates for you. The problem is that developers new to Core Data won't spot or bother with these shortcomings. And more experienced developers won't use the Core Data stack Xcode offers them because they know it won't serve them. In the end, it doesn't help anyone.

Not only is Xcode's implementation less than ideal, the application delegate class is not the best place to set up the Core Data stack of your application. I recommend to take a few minutes and create a separate class that manages the Core Data stack of your application. It makes everything related to Core Data easier to manage, more reusable, and, last but certainly not least, more testable. There are no compelling downsides to building your own solution.

The template Xcode provides you with has been updated for Swift and the concurrency API that was introduced several years ago. That said, the template still invokes the abort() function if the persistent store coordinator fails to add a persistent store. You would be surprised by the number of projects I have seen that ship with this implementation despite Apple's warning that this should not be used in production.

Project Setup

In this lesson, I want to lay the foundation for building a robust Core Data stack. Open Xcode and create a new project based on the Single View Application template. Set Language to Swift and make sure Use Core Data is unchecked.

Project Setup

Project Setup

Before we create the class that manages the Core Data stack, we need to create a data model we can work with. Create a new data model by choosing the Data Model template from the iOS > Core Data section.

Create Data Model

Create Data Model

Creating the Core Data Manager

It doesn't matter how you name the class that manages the Core Data stack. I usually stick with CoreDataManager. Create a new Swift file and name it CoreDataManager.swift.

Create Core Data Manager

Create Core Data Manager

Start by adding an import statement for the Core Data framework at the top.

import CoreData
import Foundation

Create the CoreDataManager class as shown below.

class CoreDataManager {


I would like to add a little flexibility to the CoreDataManager class by passing it the name of the data model during initialization. This makes the class more reusable.

Declare a constant property, modelName, of type String. The designated initializer of the CoreDataManager class is straightforward.

import CoreData
import Foundation

public class CoreDataManager {

    private let modelName: String

    init(modelName: String) {
        self.modelName = modelName


Open AppDelegate.swift and create a constant property of type CoreDataManager. We have already gained an advantage by creating a separate class that manages the Core Data stack. We could, for example, create an instance of the CoreDataManager class in a root view controller instead of the application delegate. That is a good start.

import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    let coreDataManager = CoreDataManager(modelName: "DataModel")

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        return true


Setting Up the Core Data Stack

You probably know that every Core Data stack is composed of three building blocks:

  • a persistent store coordinator
  • a managed object context
  • a managed object model

If you would like to learn more about the Core Data stack, I recommend reading Exploring the Core Data Stack in which I discuss each of these building blocks in more detail.

The majority of Core Data applications interact exclusively with the managed object context. This means that the Core Data manager should not expose the managed object model and the persistent store coordinator to the outside world. They can be kept private to the CoreDataManager class.

Managed Object Model

To set up the Core Data stack, we start with the managed object model. As you can see below, this is a lazy private property of the CoreDataManager class. Note that the type of the managedObjectModel property is NSManagedObjectModel?, an optional. If no data model file is found in the application bundle, the closure returns nil. We focus on error handling later in this course.

private lazy var managedObjectModel: NSManagedObjectModel? = {
    // Fetch Model URL
    guard let modelURL = NSBundle.mainBundle().URLForResource(self.modelName, withExtension: "momd") else {
        return nil

    // Initialize Managed Object Model
    let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)

    return managedObjectModel

Persistent Store Coordinator

Instantiating the persistent store coordinator is a bit more verbose. We first make sure a valid NSManagedObjectModel instance is available. If we are unable to load the data model, there is no need to instantiate the persistence store coordinator. In such a scenario, we have more serious issues to worry about.

private lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
    guard let managedObjectModel = self.managedObjectModel else {
        return nil

    // Helper
    let persistentStoreURL = self.persistentStoreURL

    // Initialize Persistent Store Coordinator
    let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)

    do {
        let options = [ NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true ]
        try persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: persistentStoreURL, options: options)

    } catch {
        let addPersistentStoreError = error as NSError

        print("Unable to Add Persistent Store")

    return persistentStoreCoordinator

We use the managed object model to instantiate the persistent store coordinator. In a do-catch block, we add a persistent store to the persistent store coordinator. In this example, the persistent store is a SQLite database.

Also note that we pass a dictionary of options as the last argument of addPersistentStoreWithType(_:configuration:URL:options:) to instruct Core Data to perform any pending migrations and infer the mapping model for any migrations. If adding the persistent store fails, we log any errors to the console. We implement more robust error handling later in this course.

In the closure of the persistentStoreCoordinator property, we use a private computed property to fetch the URL of the persistent store. The implementation is easy to understand as you can see below.

private var persistentStoreURL: NSURL {
    // Helpers
    let storeName = "\(modelName).sqlite"
    let fileManager = NSFileManager.defaultManager()

    let documentsDirectoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]

    return documentsDirectoryURL.URLByAppendingPathComponent(storeName)

Managed Object Context

Last but not least, we create the managed object context. While the implementation is not difficult, there are a few details worth pointing out.

public private(set) lazy var managedObjectContext: NSManagedObjectContext = {
    // Initialize Managed Object Context
    let managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)

    // Configure Managed Object Context
    managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator

    return managedObjectContext

While the managedObjectContext property is marked as public, the setter is private. Only the CoreDataManager instance should be allowed to set the managedObjectContext property.

We initialize the managed object context by invoking init(concurrencyType:), the designated initializer of the NSManagedObjectContext class. The first and only argument of this method is the concurrency type. By passing in .MainQueueConcurrencyType the managed object context is tied to the main queue. This means that managed object context should only be accessed from the main thread. This is a good start, but we change this later in the course to add more flexibility.

Finally, we set the persistentStoreCoordinator property of the managed object context and return the managed object context we create in the closure. Note that the managedObjectContext is of type NSManagedObjectContext.

Testing the Core Data Stack

Revisit the application delegate and update the print statement in application(_:didFinishLaunchingWithOptions:) as shown below. Run the application one more time to verify that everything is working correctly.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    return true

What's Next?

We have made a good start by implementing the CoreDataManager class. In the next lesson of this course, we revisit the managed object context. Questions? Leave them in the comments below or reach out to me on Twitter. You can find the source files on GitHub.

Next Episode "Two Is Better Than One"

Stop Writing Swift That Sucks

Download the Swift Patterns I Swear By