< Previous PageNext Page > Hide TOC

Core Data FAQ

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

Contents:

Where does a Managed Object Context Come From?
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?
How do I fetch objects in the same order I created them?
How do I copy a managed object from one context to another?
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?
How do I get undo/redo for free in my non-document-architecture-based app?
How do I create a user interface from an entity?
In Xcode’s predicate builder, why don’t I see any properties for a fetched property predicate?
When I remove objects from a detail table view managed by an array controller, why are they not removed from the object graph?
How do I get the GUI to validate the data entered by the user?
How do I initialize a store with default data?
How efficient is Core Data?
Core Data looks similar to EOF. What are the differences?


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.

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 Mac OS X you’re using and the cardinality of the relationship.

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

If you are targeting Mac OS X v10.5 and later, and 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];
}

Mac OS X v10.4 and to-many relationships on Mac OS X v10.5

If you are targeting Mac OS X v10.4, setKeys:triggerChangeNotificationsForDependentKey: does not allow key-paths, so you cannot follow the pattern described above.

If you are targeting Mac OS X v10.5, 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 release];
            totalSalary = [newTotalSalary retain];
            [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.

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, 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];
}

How do I create a user interface from an entity?

There are two ways to create a user interface from an entity: on Mac OS X v10.4 and later you use the Xcode modeling tool in conjunction with Interface Builder; on Mac OS X v10.5 and later you can also use just Interface Builder.

On Mac OS X v10.4 and later, in the Data Modeling Tool, you can Option-click an entity in the Data Modeling tool in Xcode and drag it to a window or box in Interface Builder. See NSPersistentDocument Core Data Tutorial for an example. You must make sure that Xcode is the foreground application when you do this—Option-clicking on Xcode while it is not foreground will make it foreground and hide all other applications, including Interface Builder.

On Mac OS X v10.5 and later, in Interface Builder you can drag a Core Data Entity item from the Library onto a window or box. Interface Builder then presents a panel that allows you to select the entity you want from the currently-open Xcode projects.

Note that you can also create and configure an NSController instance in Interface Builder. As in the case of creating a user interface, you Option-click an entity in the Data Modeling tool in Xcode (or select the Core Data Entity item from the Library), but you drag it to a the Interface Builder file window. For editing one object, an NSObjectController instance is created; for editing many objects, an NSArrayController instance is created.

It is important to realize that neither Xcode nor Interface Builder does anything “special” when you create an interface this way. You could create and configure the interface yourself if you wanted—it would just take longer.

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.

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.

(This is particularly relevant if you create a user interface by dragging entities from the Xcode data modeling tool. See NSPersistentDocument Core Data Tutorial for an example.)

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.

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 you are creating a document-based application using , you can follow the guideline described in NSPersistentDocument Core Data Tutorial (that is, you initialize the defaults in initWithType:error:).

If you are using a non-document-based application and started with the standard application template then after these lines of code:

if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] )
{
    [fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil];
}
url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"Delete.xml"]];

you can add a check to determine whether the file at the url exists. If it doesn't, you need to import the data.

If there is some reason that there might be a possibility that the store (hence file) gets created but the data is not imported, then you might consider adding 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 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, on Mac OS X v10.4 Core Data does not. On Mac 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.

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.



< Previous PageNext Page > Hide TOC


© 2004, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-03-04)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.