سؤال

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.

نصائح أخرى

The save will probably happen on the thread it was called on. What are the consequences? We don’t know the implementation, so we can only guess. Sometimes incorrect usage of managed contexts and managed objects can lead to a really weird behavior, and you won’t even think that that’s because of the threading mistake.

All the work with contexts and managed objects must be done on the thread or queue where they were created. Basically it is the same for traditional contexts and for contexts with private queue concurrency type. The latter just create the queue for you and always keep it with them.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top