自从升级到XCode 6.3和iOS 8.3后,我在我的应用程序中遇到一个新错误,将NSManagedObjectContexts(MOC)从后台合并到主线程MOC。
我的架构在主线程上有一个主MOC,并在其他线程上创建了几个后台MOC,这些MOC是临时的,仅用于同步新的服务器数据。当这些后台MOC保存时,我在主线程上侦听通知 NSManagedObjectContextDidSaveNotification ,并在主MOC上调用 mergeChangesFromContextDidSaveNotification 。
这是关于使用核心数据进行线程处理的文档(请参阅Core Data Concurrency)。
这曾经工作正常,但是此更新开始崩溃时出现此错误,我无法追溯到我的代码的特定行:
illegally invoked -perform* on dying NSManagedObjectContext at:
(
0 CoreData 0x28a2f273 <redacted> + 118
1 CoreData 0x28a32f09 <redacted> + 192
2 CoreFoundation 0x28c64e09 <redacted> + 12
3 CoreFoundation 0x28bbf515 _CFXNotificationPost + 1784
4 Foundation 0x29920749 <redacted> + 72
5 Foundation 0x2992522f <redacted> + 30
6 Foundation 0x29986a93 <redacted> + 98
7 Foundation 0x299867f7 <redacted> + 82
8 Foundation 0x299dfbd5 <redacted> + 408
9 CoreFoundation 0x28c72fed <redacted> + 20
10 CoreFoundation 0x28c706ab <redacted> + 278
11 CoreFoundation 0x28c709ff <redacted> + 734
12 CoreFoundation 0x28bbd201 CFRunLoopRunSpecific + 476
13 CoreFoundation 0x28bbd013 CFRunLoopRunInMode + 106
14 GraphicsServices 0x30359201 GSEventRunModal + 136
15 UIKit 0x2c361a59 UIApplicationMain + 1440
16 MyAppName 0x000c95a7 main + 170
17 libdyld.dylib 0x376c1aaf <redacted> + 2
)
我已经在XCode中打开僵尸,寻找解除分配的上下文,但没有找到任何内容。调用merge的主线程侦听器如下所示:
- (void)coreDataDidSaveNotification:(NSNotification *)notification {
NSManagedObjectContext *savedContext = (NSManagedObjectContext *)notification.object;
if (savedContext != self.mainManagedObjectContext) {
__weak typeof(self) weakSelf = self;
[self.dispatch dispatchOnMainThread:^{
NSLog(@"before merge");
[weakSelf.mainManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];
NSLog(@"after merge");
}];
}
}
日志消息“合并后”在发生崩溃之前被称为 ,这更令人困惑。我已经在通知中的后台上下文中检查了retainCount,并且在调用合并时它总是大于零,所以它不会在那时被释放。
知道发生了什么事吗?
答案 0 :(得分:2)
经过大量研究,我发现在合并完成之前,背景上下文确实已经发布了。 如果我保留对它们的引用,则崩溃永远不会发生。
看起来 mergeChangesFromContextDidSaveNotification 方法的行为已更改。持有上下文的通知足以保留它直到合并完成。
我相信现在发生的事情是 mergeChangesFromContextDidSaveNotification 方法现在内部持有弱引用,并在内部调度主线程再次上的合并,将其排入队列下一个运行循环,这就是为什么我在崩溃发生之前看到“合并后”日志的原因。当合并实际在下一个运行循环中执行时,我已经发布了对后台MOC的引用,并且当它超出范围时通知已经发布,并且因为内部引用现在可能 weak 背景MOC被解除分配。