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.

Handling Different Data Types in Core Data

Create, store, and present records for a variety of data types.

Linking Data Between Two Core Data Stores

Organize data in two different stores and implement a link between them.