Object Lifetime Management

The life-cycle of the data a managed object represents is largely independent of the lifetime of individual managed object instances. In order to add a record to a persistent store, you must allocate and initialize a managed object—and then save the managed object context. When you remove a record from a persistent store, you should ensure its corresponding managed object is eventually deallocated. In between these events, however, you can create and destroy any number of instances of a managed object that represent the same record in a given persistent store.

The Role of the Managed Object Context

Managed objects know what managed object context they’re associated with, and managed object contexts know what managed objects they contain. By default, though, the references between a managed object and its context are weak. This means that in general you cannot rely on a context to ensure the longevity of a managed object instance, and you cannot rely on the existence of a managed object to ensure the longevity of a context. Put another way, just because you fetched an object doesn’t mean it will stay around.

The exception to this rule is that a managed object context maintains a strong reference to any changed (inserted, deleted, and updated) objects until the pending transaction is committed (with a save:) or discarded (with a reset or rollback). Note that the undo manager may also keep strong references to changed objects—see “Change and Undo Management.”

You can change a context’s default behavior such that it does keep strong references to its managed objects by sending it a setRetainsRegisteredObjects: message (with the argument YES)—this makes the managed objects’ lifetimes depend on the context’s. This can be a convenience if you are caching smaller data sets in memory—for example if the context controls a temporary set of objects that may persist beyond a single event cycle, such as when editing in a sheet. It can also be useful if you are using multiple threads and passing data between them—for example if you are performing a background fetch and passing object IDs to the main thread. The background thread needs to keep strong references to the objects it pre-fetched for the main thread until it knows the main thread has actually used the object IDs to fault local instances into itself.

You should typically use a separate container to keep strong references only those managed objects you really need. You can use an array or dictionary, or an object controller (for example an NSArrayController instance) that has strong references the objects it manages. The managed objects you don’t need will then be deallocated when possible (for example, when relationships are cleared).

If you have finished with a managed object context, or for some other reason you want to “disconnect” a context from its persistent store coordinator, you should not set the context’s coordinator to nil:

// This will raise an exception.
[myManagedObjectContext setPersistentStoreCoordinator:nil];

Instead, you should simply relinquish ownership of the context and allow it to be deallocated normally.

Breaking Relationship Strong Reference Cycles

When you have relationships between managed objects, each object maintains a strong reference to the object or objects to which it is related. This can cause strong reference cycles. To ensure that reference cycles are broken, when you're finished with an object you can use the managed object context method refreshObject:mergeChanges: to turn it into a fault.

You typically use refreshObject:mergeChanges: to refresh a managed object’s property values. If the mergeChanges flag is YES, the method merges the object’s property values with those of the object available in the persistent store coordinator. If the flag is NO, however, the method simply turns an object back into a fault without merging, which causes it to break strong references to related managed objects. This breaks the strong reference cycle between that managed object and the other managed objects.

Note that, of course, before a managed object can be deallocated there must be no strong references to it, including from outside of Core Data. See also “Change and Undo Management.”

Change and Undo Management

A context keeps strong references to managed objects that have pending changes (insertions, deletions, or updates) until the context is sent a save:, reset , rollback, or dealloc message, or the appropriate number of undos to undo the change.

The undo manager associated with a context keeps strong references to any changed managed objects. By default, in OS X the context’s undo manager keeps an unlimited undo/redo stack. To limit your application's memory footprint, you should make sure that you scrub (using removeAllActions) the context’s undo stack as and when appropriate. Unless you keep a strong reference to a context’s undo manager, it is deallocated with its context.

If you do not intend to use Core Data’s undo functionality, you can reduce your application's resource requirements by setting the context’s undo manager to nil. This may be especially beneficial for background worker threads, as well as for large import or batch operations.