09 Nov 2012, 18:48
Doug_pragsmall

Doug Fales (1 post)

Hi Marcus. First, thanks for an excellent book. I’m already benefiting from the 2nd Edition in the apps I work on today.

I have a question regarding background contexts and thread confinement, especially when used with serial NSOperationQueues (max concurrency = 1).

The Apple Docs are confusing on this use case and I am hopeful that this could be addressed in your book.

First, the docs claim that you may never use an NSManagedObjectContext on a “thread” other than the one it was created on. [1]

Next, they declare that the term “single thread” and “NSOperationQueue with concurrency=1” are synonomous.[2] This is confusing as each NSOperation can technically run on a different thread, even when they are run serially in a single NSOperationQueue.

Finally, the WWDC session video seems to say that it is fine to use a context with NSConfinementConcurrencyType (the default) over multiple operations on the same serial NSOperationQueue because the control flow is always serial. [3]

The speaker says, “Core Data isn’t using any thread local state, and we’re really interested in having a single control flow. We’re not really as focused on whether or not dispatch queues work with multiple threads or how that’s happening underneath the covers.”

If you are running an NSOperationQueue as your background networking queue, it makes a lot of sense to use only a single context for that queue. For example, you can persist that queue when it makes the most logical sense in your app (maybe during a lull in network traffic, or after several operations complete), instead of at the end of each NSOperation, as you would need to if you were creating a new context at the start of each operation.

From the WWDC session, it sounds like it’s perfectly fine to create a single NSManagedObjectContext in the first NSOperation you use, and use it for the life of the serial operation queue in subsequent NSOperations as well, as long as you only reference it from the NSOperation’s main() method.

Is this something you could address in one of your sidebars in the book, like the “NSOperation and NSOperationQueue” on page 90?

Thanks again for a great book!


[1] http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html says: “If you use NSOperation, note that its init method is invoked on the same thread as the caller. You must not, therefore, create a managed object context for the queue in the queue’s init method, otherwise it is associated with the caller’s thread. Instead, you should create the context in main (for a serial queue) or start (for a concurrent queue).”

[2] http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html says: “Note: You can use threads, serial operation queues, or dispatch queues for concurrency. For the sake of conciseness, this article uses “thread” throughout to refer to any of these.”

[3] Session 214 - WWDC 2012 - At 2:28 of this session, the presenter starts to discuss the default NSConfinementConcurrencyType. At about 3:08 he explains that you can use either a serial dispatch queue or an NSOperationQueue with a maximum concurrency of one, in addition to using a specific thread for a context that has NSConfinementConcurrencyType.

19 Nov 2012, 18:37
Avatarsmall_pragsmall

Marcus S. Zarra (245 posts)

Short answer is that you should create the MOC in the -main and not the -init of the NSOperation. This will keep the MOC local to the thread that the NSOperation is on.

By doing that you do not care if the queue decides to use more than one thread or not.

Another option would be to init the moc as a background queue moc then do all of the core data work within the -performBlockAndWait:

  You must be logged in to comment