Im currently learning how to use core-data in a multithreaded environment;
I therefore created a small project with two NSManagedObjectContext
: A main NSManagedObjectContext
with NSMainQueueConcurrencyType
for reads and its child NSManagedObjectContext
with NSPrivateQueueConcurrencyType
for create/update/delete operations.
It has often been said that saving an NSManagedObjectContext
with NSPrivateQueueConcurrencyType
should be done through performBlock:
like so:
[context performBlock:^
{
Book *mutableBook = [self getMutableVersionOfBook:book];
[context deleteObject:mutableBook];
[context save:nil];
}];
What happens if the performBlock:
is omitted, like so:
Book *mutableBook = [self getMutableVersionOfBook:book];
[context deleteObject:mutableBook];
[context save:nil];
Does the save then happen on the thread the save was called on? What can happen if performBlock:
isn't used?
A private queue MOC should only be touched via a -performBlock:
or -performBlockAndWait:
. If you touch it any other way then you are violating the thread boundary rule of Core Data and you will eventually cause data corruption.
In some situations this will cause a crash in your application because violating that thread boundary is an application level error. Apple has turned that crash off a number of times and it may or may not be a crash state right now. In my opinion, It should be a crash state all the time.
As a general rule, I recommend that you use thread confined MOCs as children of the main MOC as opposed to using private MOCs. While private MOCs are nice and useful, the structure of every action must be in a block and that you cannot access the resulting NSManagedObject
instances except in those blocks is limiting. Better to spin off an operation into a queue, create a thread confined MOC in that queue and then have cleaner code than constantly having to dive into blocks (or worse create huge un-maintanable blocks).
Finally. You are passing nil
to -save:
. Never do that. You are hiding a potential problem when you do that. Even if "it is just an example", it is a terrible habit and you should break it immediately. Even in example code, pass in a NSError
and check the error. Even if you just pass the results to NSLog
you will at least avoid a surprise.