合并 NSManagedObjectContexts 之间的更改(多线程)

Posted

技术标签:

【中文标题】合并 NSManagedObjectContexts 之间的更改(多线程)【英文标题】:Merging Changes between NSManagedObjectContexts (Multithreaded) 【发布时间】:2013-06-19 12:47:31 【问题描述】:

我在合并不同 NSManagedObjectContexts(ios 6.1、Xcode 4.6)的数据时遇到问题/崩溃。

大多数时候出现的错误如下:

CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常。这通常是 NSManagedObjectContextObjectsDidChangeNotification 观察者中的一个错误。使用 userInfo (null) 的语句仍处于活动状态

有一次我得到这个错误: NSManagedObjectContextDidSaveNotification 的观察者非法抛出异常。保存的对象 = $OBJLIST 和异常 = 语句在 userInfo = (null) 时仍处于活动状态

遗憾的是,我得到的堆栈跟踪没有任何价值。它们只显示 CoreData 内部的符号(如果有的话)。

我们的 CoreData 堆栈:

1 个 NSPersistentStoreLocator 由所有线程共享 每个线程 1 个唯一的 MOC(在第一次需要时创建) 所有 MOC 都保存在字典中

为通知 NSManagedObjectContextDidSaveNotification 添加了一个观察者,以在保存到商店时更新 MOC。定义的选择器在除执行保存操作的线程/上下文之外的所有其他线程/上下文上调用 mergeChangesFromContextDidSaveNotification。

+ (void)mergeChanges:(NSNotification *)notification 
    NSManagedObjectContext *ctx;
    for ( NSNumber *threadId in [__managedObjectContexts keyEnumerator] ) 
        ctx = [__managedObjectContexts objectForKey:threadId];
        if ( notification.object != ctx ) 
            [ctx mergeChangesFromContextDidSaveNotification:notification];
        
    

产生错误的步骤:

在后台线程中,不再需要的 CoreData 数据对象(未被其他对象引用)正在被删除。

[[CDUtils managedObjectContext] deleteObject:obj];
[[CDUtils managedObjectContext] save:&error];

在此过程中,用户可以在整个应用程序中导航。用户交互(即打开一个表格视图)可以在主线程的 moc 上触发 executeFetch 调用。 每个线程都使用相同的 NSPersistentStoreLocator,但使用不同/唯一的 MOC。

我们尝试了使用 NSLocks 和 NSPersistentStoreLocator 上的锁来实现线程安全的不同锁定方法。 IE。通过锁定/解锁将mergeChanges方法和保存操作分别封闭或将这两种方法封闭在同一个锁定/解锁中。遗憾的是,到目前为止我们还没有成功。

[__storeCoordinator lock];
[__storeCoordinator unlock];

感谢您为我提供解决方案的每一条建议。感谢您的宝贵时间!

【问题讨论】:

多个上下文是否使用同一个持久存储协调器?只有一个上下文应该链接到持久存储。您可以创建子上下文来处理和导入数据,但所有保存操作都应向上合并以从单个持久存储中保存。 是的,所有 MOC 都使用相同的 PSC(根据developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/…,通常应该不是问题)。我们真的需要子上下文吗? 对于感兴趣的人。我设法使事情与多个线程/ MOC 一起工作。通过正确锁定 PSC 和 MOC,我基本上解决了最初的问题/那些错误。出现的下一个问题是如何知道它是否保存到上下文中的 mergeChanges。我不能锁定也不应该在没有运行线程的 MOC 上进行 mergeChanges。但是我怎么知道线程是否正在运行?如果我只是检查 NSThreads “isExecuting”-Method,那么线程可能会在我检查 BOOL 之后立即退出。我现在尝试一种更简单的方法,我只是合并到主线程中。 【参考方案1】:

对于感兴趣的人。我设法使事情与多个线程/ MOC 一起工作。通过正确锁定 PSC 和 MOC,我基本上解决了最初的问题/那些错误。出现的下一个问题是如何知道它是否保存到上下文中的 mergeChanges。我不能锁定也不应该在没有运行线程的 MOC 上进行 mergeChanges。但是我怎么知道线程是否正在运行?如果我只是检查 NSThreads “isExecuting”-Method,那么线程可能会在我检查 BOOL 之后立即退出。我现在尝试一种更简单的方法,我只是合并到主线程中。

【讨论】:

以上是关于合并 NSManagedObjectContexts 之间的更改(多线程)的主要内容,如果未能解决你的问题,请参考以下文章

NSFetchedResultsController 错过了合并的 NSManagedObjectContext 的更新

带有谓词的 NSFetchedResultsController 忽略从不同 NSManagedObjectContext 合并的更改

核心数据:如何在两个 NSManagedObjectContext 之间合并插入/更新/删除,同时将合并保持为可撤消的步骤?

NSManagedObjectContext 通过通知中心问题在多个线程上保存/合并

NSManagedObjectContext 从私有上下文合并,只刷新改变的对象

数据源与后台 NSManagedObjectContext 合并后 UITableView 不会重新加载