0

自从升级到 XCode 6.3 和 iOS 8.3 后,在将 NSManagedObjectContexts (MOC) 从后台合并到主线程 MOC 时,我的应用程序中出现了一个新错误。

我的架构在主线程上有一个主 MOC,并在其他线程上创建了几个后台 MOC,它们是临时的,仅用于同步新的服务器数据。当这些后台 MOC 保存时,我在主线程上监听通知NSManagedObjectContextDidSaveNotification并在主 MOC 上调用mergeChangesFromContextDidSaveNotification

这是根据关于使用 Core Data 进行线程化的文档(请参阅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 中打开了僵尸,寻找释放的上下文,但没有找到。调用合并的主线程侦听器如下所示:

- (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 并且在调用合并时它总是大于零,所以它不会在那个时候被释放。

知道发生了什么吗?

4

1 回答 1

2

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

看起来mergeChangesFromContextDidSaveNotification方法的行为已经改变。保存上下文的通知曾经足以保留它,直到合并完成。

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

于 2015-04-16T17:20:14.943 回答