magicalpanda/MagicalRecord — pull request #456 by r-peck (2013-04-20 20:18:35+00:00)
Title: Changed save actions to prevent blocking on the main thread while pushing changes through the default context

saveWithBlock: and saveWithBlockAndWait: were both using the default context as a parent context. By doing this, any saves made using those methods would block the main thread while the save propagated up the chain. By saving with the root context as a parent context, the save chain and persistence to disk both happen without blocking main thread. Entities created in this way will still be available through the default context after the save is complete. Any entities updated by the save will have their changes merged to the default context after the save to disk is complete. This increases the time until the changes are available to the default context, but keeps the main thread running in the mean time.

In addition, the asynchronous save methods were passing options to save synchronously, and all parent saves were taking place synchronously as well. Since saving up the chain happens is the last thing to happen in the block passed to the managed object context to perform, the completion block at the end of recursion will be called after all saving is complete, even without forcing the recursive saves to happen synchronously. This helped shave off some main thread time when saving the default context directly as it does not block the main thread while waiting for the root context to save to the persistent store.

I profiled by adding 100000 insertions in several of the unit tests and using the time profiler in instruments. Before the changes, I was seeing roughly 78% of time being spent on the main thread. After changes, this dropped closer to 15%. Performance when merging the changes back down to the default context will vary based on the size of the changes and the number of registered objects the default context has.