Article

Setting Up a Core Data Stack

Set up the classes that manage and persist your app’s objects.

Overview

After you create a data model file as described in Creating a Core Data Model, set up the classes that collaboratively support your app’s model layer. These classes are referred to collectively as the Core Data stack.

Diagram showing that a persistent container instance contains references to a a managed object model, a managed object context, and a persistent store coordinator that connects to your app's stores.

Initialize a Persistent Container

Typically, you initialize Core Data during your app’s startup. Create the persistent container as a lazy variable to defer instantiation until its first use in your app’s delegate.

If you selected the Core Data checkbox when creating a new Xcode project, the template automatically includes this setup code in the AppDelegate.

  1. Declare a lazy variable of type NSPersistentContainer.

  2. Create a persistent container instance, passing the data model filename to its initializer.

  3. Load any persistent stores. This call creates a store, if none exists.

class AppDelegate: UIResponder, UIApplicationDelegate {

    ...

    lazy var persistentContainer: NSPersistentContainer = {        
        let container = NSPersistentContainer(name: "DataModel")
        container.loadPersistentStores { description, error in
            if let error = error {
                fatalError("Unable to load persistent stores: \(error)")
            }
        }
        return container
    }()

    ...
}

Once created, the persistent container holds references to the model, context, and store coordinator instances in its managedObjectModel, viewContext, and persistentStoreCoordinator properties, respectively.

You can now pass a reference to the container to your user interface.

Pass a Persistent Container Reference to a View Controller

In your app’s root view controller, import Core Data and create a variable to hold a reference to a persistent container.

import UIKit
import CoreData

class ViewController: UIViewController {

    var container: NSPersistentContainer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        guard container != nil else {
            fatalError("This view needs a persistent container.")
        }
        // The persistent container is available.
    }
}

Return to your app’s delegate. In application:didFinishLaunchingWithOptions:, downcast the app window’s rootViewController to your app’s root view controller type. In this reference, set the root view controller’s container property to the persistent container.

class AppDelegate: UIResponder, UIApplicationDelegate {

    ...

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {        
        if let rootVC = window?.rootViewController as? ViewController {
            rootVC.container = persistentContainer
        }        
        return true
    }

    ...
}

To pass the persistent container to additional view controllers, repeat the creation of a container variable in each view controller, and set its value in the previous view controller’s prepareForSegue:sender:.

class ViewController: UIViewController {

    ...
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let nextVC = segue.destination as? NextViewController {
            nextVC.container = container
        }
    }
}

Subclass the Persistent Container

NSPersistentContainer is intended to be subclassed. Your subclass is a convenient place to put Core Data–related code like functions that return subsets of data and calls to persist data to disk.

import CoreData

class PersistentContainer: NSPersistentContainer {    

    func saveContext(backgroundContext: NSManagedObjectContext? = nil) {
        let context = backgroundContext ?? viewContext
        guard context.hasChanges else { return }
        do {
            try context.save()
        } catch let error as NSError {
            print("Error: \(error), \(error.userInfo)")
        }
    }    
}

The above example adds a saveContext function to the container, to improve performance by saving the context only when there are changes.

See Also

Essentials

Creating a Core Data Model

Create a data model file to contain your app’s object structure.

Core Data Stack

Manage and persist your app’s model layer.