首页 > 解决方案 > ManagedObjectContext 在编辑嵌套的对象数组时不会“变脏”

问题描述

所以我在 Core Data 中有一个实体,我们称之为 Parent 定义为:

extension Parent {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Parent> {
        return NSFetchRequest<Timer>(entityName: "Parent")
    }

    @NSManaged public var id: UUID
    @NSManaged public var children: Children
}

它有一些孩子

public class Children: NSObject, NSCoding, ObservableObject {
    @Published var children: [Child]

    init(children: [Child] = [Child]()) {
        self.cycles = cycles
    }

    // code for encoding/decoding ...
}

并且 child 对 UUID/Strings/Int 的集合有一些定义,并且是一个结构

所以最初父母显示在列表视图中要插入一个新的父母,你点击一个加号按钮,新的父母被创建并且是持久的

还有另一种视图可以将子级添加到父级

所以有什么问题?每当创建新父级时,它都会使上下文变脏并且 context.hasChanges() 返回 true 并且可以保存上下文以进行持久性

每当更新子级时,上下文不会变脏并且 context.hasChanges() 返回 false,因此不会保存更新

我认为问题是因为类是引用类型,它看起来像 Parent 并没有改变,因为 children 对象是相同的 - 但其中的数据已经改变。那么如何让更改保存?

没有删除父级并在发生更改时重新创建它或更新父级中的最后一个更新变量我没有看到我如何获得上下文以意识到有更改

标签: swiftcore-data

解决方案


tldr:不要使用可转换的属性来管理 CoreData 中的关系,使用实际的关系。

您的 CoreData 没有被标记为“脏”,因为您的 children 属性本质上是一个动态Data编码/解码的 blob。当您更新您的孩子时,不会生成任何更改通知。

虽然您可以通过这样的实现来解决当前情况:

extension Parent {

    func addChild(_ child: Child) {
        willChangeValue(forKey: #keyPath(children))
        let childrenContainer = children as? Children ?? Children()
        childrenContainer.children.append(child)
        self.children = childrenContainer
        didChangeValue(forKey: #keyPath(children))
    }

}

通常,您不会在 CoreData 中为这样的父/子关系建模,因为它比真实关系慢 6-10 倍,而且它不是如何使用 CoreData 所做的。

你可能想要的是一对多的关系

在此处输入图像描述

这将在您的代码中表现为

@NSManaged public var children: NSSet?

您也可以使用NSOrderedSet(注意ordered关系类型下方的复选框)。

您如何使用Delete Rule将取决于您希望如何对数据进行建模。Nullify将在父删除时留下孤儿,而在父删除时Cascade删除任何子。


推荐阅读