NSManagedObjectContext saving/merging over multiple threads through notifcation center issue
This is more a why does this work and that doesn't kind of question...
I am using CoreData over multiple threads. I have two threads being spawned off of the main threads and they both perform a similar call:
id observerObject = [notificationCenter addObserverForName:NSManagedObjectContextDidSaveNotification
object:secondManagedObjectContext
queue:nil
usingBlock:^(NSNotification *saveNotification) {
dispatch_async(dispatch_get_main_queue(), ^{
[mainThreadManagedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
});
}];
[secondManagedObjectContext save:nil];
[notificationCenter removeObserver:observerObject
name:NSManagedObjectContextDidSaveNotification
object:syncManagedObjectContext];
This seems to work fine, but previously I was doing this with the notification center and having some problems:
id observerObject = [notificationCenter addObserverForName:NSManagedObjectContextDidSaveNotification
object:secondManagedObjectContext
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *saveNotification) {
[mainThreadManagedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
}];
This sometimes would work, but other times XCode would pause on start up and drop a green breakpoint on the call and just list the Thread and its number, but no error. (Note: this problem on开发者_StackOverflow社区ly occurs if I spawned two or more threads).
The culprit appears to be: [NSOperationQueue mainQueue], but I cannot seem to figure out why it would make the thread pause. I was able to press continue in the debugger and just move on...but I don't understand why it was functioning this way.
I assume that I am doing something wrong and I worry that my new way might just be a hack.
Thanks for the help!
I think the first works because of the asynchronous dispatch. Without that, the notification center will pause until any particular notification completes. The problem you were getting sounds like a typical stall in which the code just pauses without error until eventually the debugger times out.
Not sure if this helps, but where you have nil for the queue try using a generic queue. Take a look at the receptionist design pattern in the apple docs.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
The merge in your first code sample is correctly dispatched on the main thread, which most probably is also the thread on which the moc was created.
In your second sample, the merge will be executed on a background thread if the notification was issued on a bg thread (notification callbacks are always called on the same thread as where the notification is posted).
BTW, instead of using the main queue, i would now rather use the NSManagedObjectContext's own performBlock:
method (>= iOS 5). On iOS5 with ARC, this code boils down to:
__weak typeof(self) weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
[weakSelf.moc performBlock:^{
[weakSelf.moc mergeChangesFromContextDidSaveNotification:note];
}];
}];
精彩评论