Guides and Sample Code

Developer

Core Data Programming Guide

On This Page

Initializing the Core Data Stack

The Core Data stack is a collection of framework objects that are accessed as part of the initialization of Core Data and that mediate between the objects in your application and external data stores. The Core Data stack handles all of the interactions with the external data stores so that your application can focus on its business logic. The stack consists of four primary objects: the managed object context (NSManagedObjectContext), the persistent store coordinator (NSPersistentStoreCoordinator), the managed object model (NSManagedObjectModel), and the persistent container (NSPersistentContainer).

You initialize the Core Data stack prior to accessing your application data. The initialization of the stack prepares Core Data for data requests and the creation of data. Here’s an example of how to create that Core Data stack.

Listing 3-1Example Core Data stack creation

Objective-C

  1. @interface MyDataController : NSObject
  2. @property (strong, nonatomic, readonly) NSPersistentContainer *persistentContainer;
  3. - (id)initWithCompletionBlock:(CallbackBlock)callback;
  4. @end
  5. @implementation MyDataController
  6. - (id)init
  7. {
  8. self = [super init];
  9. if (!self) return nil;
  10. self.persistentContainer = [[NSPersistentContainer alloc] initWithName:@"DataModel"];
  11. [self.persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *description, NSError *error) {
  12. if (error != nil) {
  13. NSLog(@"Failed to load Core Data stack: %@", error);
  14. abort();
  15. }
  16. callback();
  17. }];
  18. return self;
  19. }

Swift

  1. import UIKit
  2. import CoreData
  3. class DataController: NSObject {
  4. var managedObjectContext: NSManagedObjectContext
  5. init(completionClosure: @escaping () -> ()) {
  6. persistentContainer = NSPersistentContainer(name: "DataModel")
  7. persistentContainer.loadPersistentStores() { (description, error) in
  8. if let error = error {
  9. fatalError("Failed to load Core Data stack: \(error)")
  10. }
  11. completionClosure()
  12. }
  13. }
  14. }

This example creates a controller object that represents the persistence layer of the application. The controller is initialized with a default init call. As part of that init call, the initializeCoreData method is called, and it then proceeds to create the Core Data stack.

NSPersistentContainer

Starting in iOS 10 and macOS 10.12, the NSPersistentContainer handles the creation of the Core Data stack and offers access to the NSManagedObjectContext as well as a number of convenience methods. Prior to iOS 10 and macOS 10.12, the creation of the Core Data stack was more involved.

Objective-C

  1. - (id)initWithCompletionBlock:(CallbackBlock)callback;
  2. {
  3. self = [super init];
  4. if (!self) return nil;
  5. //This resource is the same name as your xcdatamodeld contained in your project
  6. NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Workspace" withExtension:@"momd"];
  7. NSAssert(modelURL, @"Failed to locate momd bundle in application");
  8. // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
  9. NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
  10. NSAssert(mom, @"Failed to initialize mom from URL: %@", modelURL);
  11. NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
  12. NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
  13. [moc setPersistentStoreCoordinator:coordinator];
  14. [self setManagedObjectContext:moc];
  15. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
  16. NSPersistentStoreCoordinator *psc = [[self managedObjectContext] persistentStoreCoordinator];
  17. NSFileManager *fileManager = [NSFileManager defaultManager];
  18. NSURL *documentsURL = [[fileManager URLsForDirectory:NSDocumentationDirectory inDomains:NSUserDomainMask] lastObject];
  19. // The directory the application uses to store the Core Data store file. This code uses a file named "DataModel.sqlite" in the application's documents directory.
  20. NSURL *storeURL = [documentsURL URLByAppendingPathComponent:@"DataModel.sqlite"];
  21. NSError *error = nil;
  22. NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];
  23. if (!store) {
  24. NSLog(@"Failed to initalize persistent store: %@\n%@", [error localizedDescription], [error userInfo]);
  25. abort();
  26. //A more user facing error message may be appropriate here rather than just a console log and an abort
  27. }
  28. if (!callback) {
  29. //If there is no callback block we can safely return
  30. return;
  31. }
  32. //The callback block is expected to complete the User Interface and therefore should be presented back on the main queue so that the user interface does not need to be concerned with which queue this call is coming from.
  33. dispatch_sync(dispatch_get_main_queue(), ^{
  34. callback();
  35. });
  36. });
  37. return self;
  38. }

Swift

  1. init(completionClosure: @escaping () -> ()) {
  2. //This resource is the same name as your xcdatamodeld contained in your project
  3. guard let modelURL = Bundle.main.url(forResource: "DataModel", withExtension:"momd") else {
  4. fatalError("Error loading model from bundle")
  5. }
  6. // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
  7. guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
  8. fatalError("Error initializing mom from: \(modelURL)")
  9. }
  10. let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
  11. managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.mainQueueConcurrencyType)
  12. managedObjectContext.persistentStoreCoordinator = psc
  13. let queue = DispatchQueue.global(qos: DispatchQoS.QoSClass.background)
  14. queue.async {
  15. guard let docURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
  16. fatalError("Unable to resolve document directory")
  17. }
  18. let storeURL = docURL.appendingPathComponent("DataModel.sqlite")
  19. do {
  20. try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
  21. //The callback block is expected to complete the User Interface and therefore should be presented back on the main queue so that the user interface does not need to be concerned with which queue this call is coming from.
  22. DispatchQueue.main.sync(execute: completionClosure)
  23. } catch {
  24. fatalError("Error migrating store: \(error)")
  25. }
  26. }
  27. }

In addition to simplifying the construction of the Core Data stack, the NSPersistentContainer also has a number of convenience methods that assist the developer when working with multithreaded applications.

NSManagedObjectModel

The NSManagedObjectModel instance describes the data that is going to be accessed by the Core Data stack. During the creation of the Core Data stack, the NSManagedObjectModel is loaded into memory as the first step in the creation of the stack. The example code above resolves an NSURL from the main application bundle using a known filename (in this example DataModel.momd) for the NSManagedObjectModel. After the NSManagedObjectModel object is initialized, the NSPersistentStoreCoordinator object is constructed.

NSPersistentStoreCoordinator

The NSPersistentStoreCoordinator sits in the middle of the Core Data stack. The coordinator is responsible for realizing instances of entities that are defined inside of the model. It creates new instances of the entities in the model, and it retrieves existing instances from a persistent store (NSPersistentStore). The persistent store can be on disk or in memory. Depending on the structure of the application, it is possible, although uncommon, to have more than one persistent store being coordinated by the NSPersistentStoreCoordinator.

Whereas the NSManagedObjectModel defines the structure of the data, the NSPersistentStoreCoordinator realizes objects from the data in the persistent store and passes those objects off to the requesting NSManagedObjectContext. The NSPersistentStoreCoordinator also verifies that the data is in a consistent state that matches the definitions in the NSManagedObjectModel.

The call to add the NSPersistentStore to the NSPersistentStoreCoordinator is performed asynchronously. A few situations can cause this call to block the calling thread (for example, integration with iCloud and Migrations). Therefore, it is better to execute this call asynchronously to avoid blocking the user interface queue.

NSManagedObjectContext

The managed object context (NSManagedObjectContext) is the object that your application will interact with the most, and therefore it is the one that is exposed to the rest of your application. Think of the managed object context as an intelligent scratch pad. When you fetch objects from a persistent store, you bring temporary copies onto the scratch pad where they form an object graph (or a collection of object graphs). You can then modify those objects however you like. Unless you actually save those changes, however, the persistent store remains unaltered.

All managed objects must be registered with a managed object context. You use the context to add objects to the object graph and remove objects from the object graph. The context tracks the changes you make, both to individual objects’ attributes and to the relationships between objects. By tracking changes, the context is able to provide undo and redo support for you. It also ensures that if you change relationships between objects, the integrity of the object graph is maintained.

If you choose to save the changes you have made, the context ensures that your objects are in a valid state. If they are, the changes are written to the persistent store (or stores), new records are added for objects you created, and records are removed for objects you deleted.

Without Core Data, you have to write methods to support archiving and unarchiving of data, to keep track of model objects, and to interact with an undo manager to support undo. In the Core Data framework, most of this functionality is provided for you automatically, primarily through the managed object context.