【问题标题】:Why might Core Data fail to merge data from private context to main context?为什么 Core Data 无法将数据从私有上下文合并到主上下文?
【发布时间】:2017-06-13 19:49:56
【问题描述】:

我有一个使用 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,它会在保存私有上下文并将更改合并到主上下文时调用以下函数:

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)
            })
        }
    }
}

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

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

【问题讨论】:

  • 您如何测试主上下文中的托管对象不同步?
  • 如果您只支持 iOS 10+,那么您可以使用 automaticallyMergesChangesFromParent 来为您处理。
  • if savedContext == privateObjectContext { 行中的 privateObjectContext 是主上下文的父级还是兄弟级?
  • 我通过在调用mainObjectContext.mergeChangesFromContextDidSaveNotification(notification) 之前和之后记录对象(使用mainObjectContext.objectWithID(_:))来测试它们是否不同步。我还记录了notification.userInfo?[NSUpdatedObjectsKey] 值,因为它们代表私有上下文中对象的状态。而 privateObjectContext 是主上下文的兄弟

标签: ios swift core-data


【解决方案1】:

我曾经使用与您类似的结构,但在我的情况下它并不可靠。有时它确实有效,有时它没有。就像您描述的那样,其中一个错误是“不完整的合并”。我在 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

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

当使用 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 来完成繁重的工作。

在所有数据都被消费并转化为 NSManagedObject 实例,您在私有上下文中调用 save ,它 将所有更改移动到主队列上下文中而不阻塞 主队列。

【讨论】:

    【解决方案2】:

    您不能合并同级上下文。您必须从父级向下合并。换句话说,改变

     if savedContext == privateObjectContext {
    

     if savedContext == savingObjectContext {
    

    savingObjectContext 是主上下文的父上下文。

    【讨论】:

    • 是什么让你说兄弟上下文不能合并?有没有你可以引用的文档来支持它?这个答案:stackoverflow.com/a/24663533 显示了两个常见的托管对象上下文层次结构,其中数据在同级之间合并。
    【解决方案3】:

    您始终可以将 mainQueueContext 设置为您的 privateQueueContext 的父级:

    privateObjectContext.parent = mainObjectContext
    

    这会将您的保存合并到您的主要对象上下文中。我在解析 JSON 的项目中使用了它,并在 privateQueue 的执行块中设置核心数据对象,并将我的 mainContext 设置为父级。然后我简单地保存私有,然后从主线程/主上下文访问数据。奇迹般有效。我应该补充一点,我不会将私有上下文保存在内存中,它会在我需要时创建新的。

    【讨论】:

    • 这确实有效,但从性能的角度来看它并不理想,因为从私有对象上下文完成的所有数据获取和保存回持久存储都必须“拉”/“推”通过主队列上下文。
    【解决方案4】:

    问题在于您的合并策略。尝试更改为 NSErrorMergePolicy,我认为您将开始看到合并冲突。至少这会让你对根本原因有更多的了解

    【讨论】:

    • 我已尝试将所有托管对象上下文的合并策略更改为 NSErrorMergePolicy,但从任何一个私有队列上下文保存时都没有遇到任何错误。
    猜你喜欢
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多