First, a little background.

What is an NSManagedObjectContext?

An NSManagedObjectContext manages a collection of NSManagedObject s. At it’s core, the managed object context’s primary role is change management. As the managed objects owned by the context change it observes the changes and updates it’s in-memory representation of the object graph. During a save, these changes are aggregated and commited as a transaction. Managed object contexts are lightweight and easy to create. It has long been a best practice to create a new context for any unit of work or set of changes to be performed on the context.

Over it’s lifetime, Core Data has supported several different models of concurrency for working with the object graph. Which of these models your application uses greatly influences how it interacts with NSManagedObjectContext s.

Thread Confinement

An NSManagedObjectContext using thread confinement should only be accessed by the thread it was created from. When an NSManagedObjectContext is created with the initializer -[initWithConcurrencyType:NSConfinementConcurrencyType] the context is using thread confinement. To retain backwards compatiblity with older code, the initializer -[init] is actually just a wrapper for -[initWithConcurrencyType:NSConfinementConcurrencyType] . They are equivalent.

Thread confinement is the model described by the Core Data Programming Guide section Concurrency With Core Data even though thread confinement is considered obsolete and is not recommended for new code or new projects.

Queue Confinement

iOS 5 and MacOS X 10.7 introduced the queue confinement model. When an NSManagedObjectContext is created with the initializer initWithConcurrencyType:NSPrivateQueueConcurrencyType] or -[initWithConcurrencyType:NSMainQueueConcurrencyType] all access to the context and it’s managed objects must go through the method -[performBlock: or -[performBlockAndWait:] . Core Data is using a serial queue to ensure that operations on the context are performed in order, and that only one operation is happening at a time. This allows the context to be accessed from any thread safely, and can be done asynchronously using -[performBlock:] . The principles behind this are described in the Concurrency Programming Guide

This is a huge improvement over thread confinement, which never worked very well. Unfortunately, the Core Data Programming Guide does not contain any information on queue confinement. Most of the available documentation is in the NSManagedObject Class Reference or the Core Data Release Notes for iOS 5 and MacOS 10.7 .

How Contexts Communicate Changes

The two different concurrency models come with two different methods of communicating changes between NSManagedObjectContext s.

Using thread confinement, the application would observe an NSManagedObjectContext using the NSManagedObjectContextDidSaveNotification notification. When that notifcation was received, the notifcation payload contained references to objects changed in that context, which would then be merged into other contexts using the method -[mergeChangesFromContextDidSaveNotification:] .

This animation illustrates the process:

How obsolete NSManagedObjectContexts propagate changes from Dan Z on Vimeo.

This has a number of drawbacks. The notification arrives on the thread that owns the context that performed the save, rather than that of the receiver. Tracking which contexts should merge with which other contexts is not trivial in a complex application. Merges using this method were never very performant, as there would often be many irrelevant changes which still needed to be processed. A typical application might have several threads doing work that needed to be merged into the main thread’s context to be represented in the user interface, which would in turn make the main thread very busy resolving and applying changes.

The queue confinement model arrived hand in hand with the concept of nested contexts. Rather than using notifications to communicate changes between contexts, contexts now have parent-child relationships. When a child context is saved those changes are pushed to the parent context immediately and efficiently.

This animation illustrates how nested contexts communicate changes:

Core Data: How nested contexts propagate change from Dan Z on Vimeo.

Things to know

It is generally not a good idea to mix communication methods between different concurrency models. When using queue confinement, use nested contexts and only nested contexts to communicate changes. Do not attempt to get away with using NSManagedObjectContextDidSaveNotification . It will not work correctly and reliably, and will reintroduce some of the drawbacks of the thread confinement model.