1

就像在许多应用程序中一样,我有一个项目列表(由 Core Data 获取请求填充)、一个用于创建新项目的工作表,以及一个用于在点击列表中的一行时编辑项目的工作表。我正在尝试统一两个表单以创建和编辑更新,并将取消/保存逻辑放在表单的超级视图中。

所以我有这样的事情:

  • ListView:由 Core Data 获取请求填充的行列表
  • AddView:带有 FormView 嵌入 + 取消和保存按钮的 NavigationView
  • EditView:带有 FormView 嵌入 + 取消和保存按钮的 NavigationView
  • FormView:一个TextField,用于更新项目的名称

在 AddView 的 init() 中,我在没有任何上下文的情况下创建了一个新的 NSManagedObject(我这样做是因为我不希望在 AddView 中创建新项目时更新我的​​ ListView,但只有当我保存此项目时 - > 替代方法可能是使用子上下文,或根据返回对象的 isInserted 或 objectID.isTemporaryID 过滤获取请求结果)。AddView 包含一个带有 FormView 嵌入的 NavigationView、一个取消按钮和一个保存按钮。此保存按钮基于托管对象上的计算属性被禁用(对象名称不能为 nil)。

在 EditView 中,我传递了从 ListView 中点击的项目。此项目是附加到应用程序主 viewContext 的现有 NSManagedObject(来自 ListView 的获取请求)。EditView 包含一个带有 FormView 嵌入的 NavigationView、一个取消按钮和一个保存按钮(与 AddView 完全相同)。基于相同的计算属性,此保存按钮也被禁用。

我的问题是,当我从 FormView 中的 TextField 更新项目名称时,启用/禁用保存按钮的条件不适用于 AddView(当我从 FormView 更改项目名称时,此 AddView 实际上没有刷新) 但适用于 EditView(当我从 FormView 更改项目名称时,此 EditView 会刷新)。如果我在 AddView 的 init() 中将上下文附加到新的 NSManagedObject,则条件就像在 EditView 中一样。

因此,SwiftUI 似乎没有观察到没有任何上下文的 NSManagedObject?我错过了什么还是这是一个错误?

4

2 回答 2

0

如果托管对象的更改通知能力取决于上下文的存在,我不会感到惊讶(但尚未验证)。我想不出你想在没有上下文的情况下创建托管对象的情况。

您应该使用子上下文。上下文在 Core Data 中为您做了很多工作(管理关系,可能更改通知,验证等),并提供了一种简单的方法来取消/保存更改 - 只需保存子上下文,数据流回主上下文,或丢弃要放弃的上下文。

于 2020-11-03T11:12:51.547 回答
0

获取更改通知的解决方法是将此覆盖添加到 NSManagedObject 子类:

override public func willChangeValue(forKey key: String) {
    super.willChangeValue(forKey: key)
    self.objectWillChange.send()
}

NSManagedObject 可以被子类化以添加这个覆盖(更多信息在这里这里


如果我们不想触发每个键的更改,我们可以更具体地了解更新值。这也适用于关系(上述解决方案并非如此)。

func setName(_ name: String) {
    objectWillChange.send()
    self.name = name
}

在这种情况下,即使观察到的对象没有上下文,我的 AddView 也会更新(更改通知可能仅在对象存在上下文时触发)。保存按钮根据我的 NSManagedObject 子类中的以下计算属性被禁用/启用。

var canBeSaved: Bool {
    if self.name.isEmpty {
       return false
    } else {
       return true
    }
}
于 2020-11-03T14:27:13.787 回答