NSManagedObjectContext 通过通知中心问题在多个线程上保存/合并
这更多的是为什么它能起作用,这不是问题……
我在多个线程上使用 CoreData。我有两个线程从主线程中产生,它们都执行类似的调用:
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];
这似乎工作正常,但之前我是通过通知中心执行此操作并遇到一些问题:
id observerObject = [notificationCenter addObserverForName:NSManagedObjectContextDidSaveNotification
object:secondManagedObjectContext
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *saveNotification) {
[mainThreadManagedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
}];
这有时会起作用,但有时 XCode 会启动时暂停并在调用上放置一个绿色断点,仅列出线程及其编号,但没有错误。 (注意:只有当我生成两个或更多线程时才会出现此问题)。
罪魁祸首似乎是:[NSOperationQueue mainQueue],但我似乎无法弄清楚为什么它会使线程暂停。我能够在调试器中按“继续”并继续...但我不明白为什么它会以这种方式运行。
我认为我做错了什么,我担心我的新方法可能只是一种黑客行为。
感谢您的帮助!
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 only 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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为第一个之所以有效是因为异步调度。否则,通知中心将暂停,直到任何特定通知完成。您遇到的问题听起来像是一个典型的停顿,其中代码只是暂停而没有错误,直到最终调试器超时。
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.
第一个代码示例中的合并已在主线程上正确分派,该主线程很可能也是创建 moc 的线程。
在第二个示例中,如果通知是在 bg 线程上发出的,则合并将在后台线程上执行(通知回调始终在与发布通知的线程相同的线程上调用)。
顺便说一句,我现在宁愿使用 NSManagedObjectContext 自己的
performBlock:
方法(>= iOS 5),而不是使用主队列。在带有 ARC 的 iOS5 上,此代码可归结为: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: