Core Data FAQ

This document provides answers to questions frequently asked about Core Data.

Where does a Managed Object Context Come From?

Where a managed object context comes from is entirely application-dependent. In a Cocoa document-based application using NSPersistentDocument, the persistent document typically creates the context, and gives you access to it through the managedObjectContext method.

In a single-window application, if you create your project using the standard project assistant, the application delegate (the instance of the AppDelegate class) again creates the context, and gives you access to it through the managedObjectContext method. In this case, however, the code to create the context (and the rest of the Core Data stack) is explicit. It is written for you automatically as part of the template.

Note that you should not use instances of subclasses of NSController directly to execute fetches (for example, you should not create an instance of NSArrayController specifically to execute a fetch). Controllers are for managing the interaction between your model objects and your human interface. At the model object level, you should just use a managed object context to perform the fetches directly.

How do I initialize a store with default data?

There are two issues here: creating the data, and ensuring the data is imported only once.

There are several ways to create the data.

There are also several ways to ensure that the defaults are imported only once:

If there is a possibility that the store (hence file) might be created but the data not imported, then you can add a metadata flag to the store. You can check the metadata (using metadataForPersistentStoreWithURL:error:) more efficiently than executing a fetch (and it does not require you to hard code any default data values).

How do I use my existing SQLite database with Core Data?

You don’t. Although Core Data supports SQLite as one of its persistent store types, the database format is private. You cannot create a SQLite database using native SQLite API and use it directly with Core Data (nor should you manipulate an existing Core Data SQLite store using native SQLite API). If you have an existing SQLite database, you need to import it into a Core Data store (see “Efficiently Importing Data”).

I have a to-many relationship from Entity A to Entity B. How do I fetch the instances of Entity B related to a given instance of Entity A?

You don’t. More specifically, there is no need to explicitly fetch the destination instances, you simply invoke the appropriate key-value coding or accessor method on the instance of Entity A. If the relationship is called “widgets”, then if you have implemented a custom class with a similarly named accessor method, you simply write:

NSSet *asWidgets = [instanceA widgets];

Otherwise you use key-value coding:

NSMutableSet *asWidgets = [instanceA mutableSetValueForKey:@"widgets"];

How do I fetch objects in the same order I created them?

Objects in a persistent store are unordered. Typically you should impose order at the controller or view layer, based on an attribute such as creation date. If there is order inherent in your data, you need to explicitly model that.

How do I copy a managed object from one context to another?

First, note that in a strict sense you are not copying the object. You are conceptually creating an additional reference to the same underlying data in the persistent store.

To copy a managed object from one context to another, you can use the object’s object ID, as illustrated in the following example.

NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *copy = [context2 objectWithID:objectID];

I have a key whose value is dependent on values of attributes in a related entity—how do I ensure it is kept up to date as the attribute values are changes and as the relationship is manipulated?

There are many situations in which the value of one property depends on that of one or more other attributes in another entity. If the value of one attribute changes, then the value of the derived property should also be flagged for change. How you ensure that key-value observing notifications are posted for these dependent properties depends on which version of OS X you’re using and the cardinality of the relationship.

OS X v10.5 and later for a to-one relationship

If there is a to-one relationship to the related entity, then to trigger notifications automatically you should either override keyPathsForValuesAffectingValueForKey: or implement a suitable method that follows the pattern it defines for registering dependent keys.

For example, you could override keyPathsForValuesAffectingValueForKey: as shown in the following example:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
 
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
 
    if ([key isEqualToString:@"fullNameAndDepartment"]) {
 
        NSSet *affectingKeys = [NSSet setWithObjects:@"lastName", @"firstName",
                                                     @"department.deptName", nil];
        keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKeys];
    }
    return keyPaths;
}

Or, to achieve the same result, you could just implement keyPathsForValuesAffectingFullNameAndDepartment as illustrated in the following example:

+ (NSSet *)keyPathsForValuesAffectingFullNameAndDepartment {
 
    return [NSSet setWithObjects:@"lastName", @"firstName",
                                 @"department.deptName", nil];
}

To-many relationships

keyPathsForValuesAffectingValueForKey: does not allow key-paths that include a to-many relationship. For example, suppose you have an Department entity with a to-many relationship (employees) to a Employee, and Employee has a salary attribute. You might want the Department entity have a totalSalary attribute that is dependent upon the salaries of all the Employees in the relationship. You can not do this with, for example, keyPathsForValuesAffectingTotalSalary and returning employees.salary as a key.

There are two possible solutions in both situations:

  1. You can use key-value observing to register the parent (in this example, Department) as an observer of the relevant attribute of all the children (Employees in this example). You must add and remove the parent as an observer as child objects are added to and removed from the relationship (see “Registering for Key-Value Observing”). In the observeValueForKeyPath:ofObject:change:context: method you update the dependent value in response to changes, as illustrated in the following code fragment:

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
     
        if (context == totalSalaryContext) {
            [self updateTotalSalary];
        }
        else
        // Deal with other observations and/or invoke super...
    }
     
    - (void)updateTotalSalary {
     
        [self setTotalSalary:[self valueForKeyPath:@"employees.@sum.salary"]];
    }
     
    - (void)setTotalSalary:(NSNumber *)newTotalSalary
    {
        if (totalSalary != newTotalSalary) {
            [self willChangeValueForKey:@"totalSalary"];
            totalSalary = newTotalSalary;
            [self didChangeValueForKey:@"totalSalary"];
        }
    }
     
    - (NSNumber *)totalSalary {
     
        return totalSalary;
    }
  2. You can register the parent with the application's notification center as an observer of its managed object context. The parent should respond to relevant change notifications posted by the children in a manner similar to that for key-value observing.

In Xcode’s predicate builder, why don’t I see any properties for a fetched property predicate?

If you want to create a predicate for a fetched property in the predicate builder in Xcode, but don’t see any properties, you have probably not set the destination entity for the fetched property.

How efficient is Core Data?

Throughout the development of Core Data, the engineering team compared the runtime performance of a generic Core Data application with that of a similar application developed without using Core Data. In general, the Core Data implementation performed better. There may nevertheless be opportunities for further optimization, and the team continues to pursue performance aggressively. For a discussion of how you can ensure you use Core Data as efficiently as possible, see “Core Data Performance.”

Core Data looks similar to EOF. What are the differences?

Core Data and EOF (the Enterprise Objects Framework that ships with WebObjects) share a common heritage, but have different goals. EOF is a Java-based framework that connects as a client to a database server. Core Data is an Objective-C-based framework designed to support desktop application development. Core Data supports a number of features not supported by EOF, and vice-versa.

Features Supported Only by EOF

EOF allows you to use custom SQL, shared editing contexts, and nested editing contexts. Core Data does not provide the equivalent of an EOModelGroup—the NSManagedObjectModel class provides methods for merging models from existing models, and for retrieving merged models from bundles.

EOF supports pre-fetching and batch faulting of relationships, in OS X v10.4 Core Data does not. In OS X v10.5, when you create a fetch request, you can use setRelationshipKeyPathsForPrefetching: to specify key paths for relationships that should be fetched with the target entity.

Features Supported Only by Core Data

Core Data supports fetched properties; multiple configurations within a managed object model; local stores; store aggregation (the data for a given entity may be spread across multiple stores); customization and localization of property names and validation warnings; and the use of predicates for property validation.

Class Mapping

There are parallels between many of the classes in Core Data and EOF.

  • NSManagedObject corresponds to EOGenericRecord.

  • NSManagedObjectContext corresponds to EOEditingContext.

  • NSManagedObjectModel corresponds to EOModel.

  • NSPersistentStoreCoordinator corresponds to EOObjectStoreCoordinator.

  • NSEntityDescription, NSPropertyDescription, NSRelationshipDescription, and NSAttributeDescription correspond to EOEntity, EOProperty, EORelationship, and EOAttribute respectively.

Change Management

There is an important behavioral difference between EOF and Core Data with respect to change propagation. In Core Data, peer managed object contexts are not "kept in sync" in the same way as editing contexts in EOF. Given two managed object contexts connected to the same persistent store coordinator, and with the "same" managed object in both contexts, if you modify one of the managed objects then save, the other is not re-faulted (changes are not propagated from one context to another). If you modify then save the other managed object, then (at least if you use the default merge policy) you will get an optimistic locking failure.

Multi-Threading

The policy for locking a Core Data managed object context in a multithreaded environment is not the same policy as for an editing context in EOF.

OS X Desktop

These questions are only relevant to OS X/desktop.

How do I get the GUI to validate the data entered by the user?

Core Data validates all managed objects when a managed object context is sent a save: message. In a Core Data document-based application, this is when the user saves the document. You can have the GUI validate it as the data is being entered by selecting the “Validates Immediately” option for a value binding in the Interface Builder bindings inspector. If you establish the binding programmatically, you supply in the binding options dictionary a value of YES (as an NSNumber object) for the key NSValidatesImmediatelyBindingOption (see “Binding Options”).

For details of how to write custom validation methods, see the subclassing notes for NSManagedObject.

When I remove objects from a detail table view managed by an array controller, why are they not removed from the object graph?

If an array controller manages the collection of objects at the destination of a relationship, then by default the remove method simply removes the current selection from the relationship. If you want removed objects to be deleted from the object graph, then you need to enable the “Deletes Objects On Remove” option for the contentSet binding.

How do I get undo/redo for free in my non-document-architecture-based app?

In a Core Data document-based application, the standard NSDocument undo manager is replaced by the document’s managed object context’s undo manager. In a non-document-based application for desktop OS X, your window’s delegate can supply the managed object context’s undo manager using the windowWillReturnUndoManager: delegate method. If your window delegate has an accessor method for the managed object context (as is the case if you use the Core Data Application template), your implementation of windowWillReturnUndoManager: might be as follows.

- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)sender {
    return [[self managedObjectContext] undoManager];
}