We have an iOS app that uses MagicalRecord for CoreData. I've been working on freeing up our main thread and putting more of our processing onto background threads. We had been using the MR_contextForCurrentThread method, which has been deprecated, and my first attempt was to replace it with short-lived worker contexts via saveWithBlock, as suggested in this blog post:
I ran into an issue, however, where the same managed objects were being created/deleted/updated in multiple short-lived background worker contexts at the same time, which resulted in concurrency issues on saving. I addressed this by creating a single background worker context, which is stored in a static variable similar to how the MagicalRecord defaultContext and rootContext are stored, and performing all operations against this one worker context using performBlock.
This successfully worked around the save concurrency issues, but I am wondering whether using a long-lived background worker context like this is really a solid approach. In the blog post referenced above, Saul Mora writes:
"Say you have a context created via the contextForCurrentThread method, and then hold on to a reference to that context. You then submit more blocks onto the queue, and use the same context. There is an eventual possibility that one or more of the newly submitted blocks will be run on a thread that is not the thread in which the context was created. And, while this alone doesn't mean sudden death for your app, there will eventually be a crash because the context was access on the wrong thread, even though the queue is the same."
I'm wondering, if the above is really true, why it doesn't affect the static rootContext object (which is a private queue context) that is used within MagicalRecord. The defaultContext (main queue context) wouldn't be vulnerable to this GCD queue/thread swapping potential, but I would think the rootContext would be, as save blocks in particular are executed against its private queue all the time.
If a long-lived context really isn't safe to use even if it is always handled using performBlock, then what is the recommended strategy for handling background operations that may be operating on the same managed objects concurrently?