ios - 为什么 Core Data 无法将私有(private)上下文中的数据合并到主上下文中?

标签 ios swift core-data

我有一个使用 Core Data 的应用程序,具有以下相当标准的托管对象上下文层次结构:

Persistent Store Coordinator 
    ↳ Save Context (Private Queue Concurrency Type) 
        ↳ Main Context (Main Queue Concurrency Type)
        ↳ Private Context (Private Queue Concurrency Type)

所有托管对象上下文的合并策略设置为 NSMergeByPropertyObjectTrumpMergePolicy

我正在观察 NSManagedObjectContextDidSaveNotification,它将在保存私有(private)上下文并将更改合并到主上下文时调用以下函数:

func contextDidSaveNotificationHandler(notification: NSNotification) {

    if let savedContext = notification.object as? NSManagedObjectContext {
        if savedContext == privateObjectContext {

            mainObjectContext.performBlock({

                if let updatedObjects = notification.userInfo![NSUpdatedObjectsKey] as? Set<NSManagedObject> {
                    //
                    // fire faults on the updated objects
                    //
                    for obj in updatedObjects {
                        mainObjectContext.objectWithID(obj.objectID).willAccessValueForKey(nil)
                    }
                }

                mainObjectContext.mergeChangesFromContextDidSaveNotification(notification)
            })
        }
    }
}

这大部分时间都有效,但有时我发现对私有(private)上下文中现有对象的更改没有合并到主上下文中。我不明白为什么——私有(private)上下文保存成功; NSManagedObjectContextDidSaveNotification 通知正在发送;正在调用通知处理程序; notification.userInfo?[NSUpdatedObjectsKey] 包含正确更新的对象;但最后,主上下文与私有(private)上下文不同步。 (即:主上下文中的托管对象与 notification.userInfo?[NSUpdatedObjectsKey] 中包含的值不同步)如果我终止应用程序并重新启动它,上下文将再次同步(在从持久存储加载对象)。

我在启动参数中启用了 -com.apple.CoreData.ConcurrencyDebug 1,并且所有 Core Data 多线程规则都得到了遵守。我看不到我的托管对象上下文层次结构或合并函数有任何明显的错误。可能是什么原因造成的?

最佳答案

我曾经使用过与您类似的结构,但在我的情况下它并不可靠。有时它确实有效,有时却没有。正如您所描述的,其中一个错误是“不完整的合并”。我开始在 iOS 10 中观察到这种行为。我相信 Core Data 的核心可能发生了一些变化。

无论如何,我改变了我的方法。我开始在 Core Data/Concurrency 上使用 Apple 的示例代码:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/Concurrency.html#//apple_ref/doc/uid/TP40001075-CH24-SW3

如果您阅读整个页面(不是那么大),您可能会注意到他们建议像往常一样创建一个私有(private)队列,但是:

This example can be further simplified when using an NSPersistentContainer:

let jsonArray = …
let container = self.persistentContainer
container.performBackgroundTask() { (context) in
    for jsonObject in jsonArray {
        let mo = EmployeeMO(context: context)
        mo.populateFromJSON(jsonObject)
    }
    do {
        try context.save()
    } catch {
        fatalError("Failure to save context: \(error)")
    }
}

当然,我不确定上面的代码是否完全符合您的要求。然而,关键是要依靠 persistentContainer 来完成繁重的工作。

After all of the data has been consumed and turned into NSManagedObject instances, you call save on the private context, which moves all of the changes into the main queue context without blocking the main queue.

关于ios - 为什么 Core Data 无法将私有(private)上下文中的数据合并到主上下文中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41905684/

相关文章:

ios - 为什么我的 UITableViewCell 不取消选择并更新它的文本?

ios - 当用户移动 map 时阻止 MKMapView 移动到用户的当前位置

iphone - 如何解析 iOS 中有特殊字符的 xml 数据?

Swift 无法让 UICollectionView 正确布局

objective-c - 哪个持久内存是更好的选择?

ios - 容器 View Controller 无法处理 Unwind Segue 操作

ios - 将 Google map 相机移动到某个位置

ios - Realm 快速通知停止触发

ios - NSManagedObject 循环返回重复项 Swift

ios - 什么是我的应用程序的更好选择 - CoreData 或 plist?