核心数据崩溃时出现错误“dying managedobjectcontext”

时间:2015-04-16 17:20:15

标签: ios objective-c multithreading core-data xcode6.3

自从升级到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,并且在调用合并时它总是大于零,所以它不会在那时被释放。

知道发生了什么事吗?

1 个答案:

答案 0 :(得分:2)

经过大量研究,我发现在合并完成之前,背景上下文确实已经发布了。 如果我保留对它们的引用,则崩溃永远不会发生。

看起来 mergeChangesFromContextDidSaveNotification 方法的行为已更改。持有上下文的通知足以保留它直到合并完成。

我相信现在发生的事情是 mergeChangesFromContextDidSaveNotification 方法现在内部持有弱引用,并在内部调度主线程再次上的合并,将其排入队列下一个运行循环,这就是为什么我在崩溃发生之前看到“合并后”日志的原因。当合并实际在下一个运行循环中执行时,我已经发布了对后台MOC的引用,并且当它超出范围时通知已经发布,并且因为内部引用现在可能 weak 背景MOC被解除分配。