NSManagedObject 更改不会触发 objectWillChange

whi*_*ler 9 core-data swift swiftui combine

我有一个核心数据模型,其中一个实体生成到 class 中Task。我正在尝试objectWillChangeNSManagedObject发送(自动,无需手动工作)中获取合并发布者,但它不会。任务实体有一个name属性。

let task = Task(context: container.viewContext)

let taskSubscription = task.objectWillChange.sink(receiveValue: { _ in
    print("Task changed")
})

task.name = "Foo"              // WILL NOT trigger
Run Code Online (Sandbox Code Playgroud)

如果我手动调用发送,订阅将起作用:

task.objectWillChange.send()   // Will trigger
Run Code Online (Sandbox Code Playgroud)

如果我用一个 simple 替换ObservableObject它,它将按预期工作:

class DummyTask: ObservableObject {
    @Published var name: String?
}
Run Code Online (Sandbox Code Playgroud)
let dummy = DummyTask()
let dummySubscription = dummy.objectWillChange.sink(receiveValue: { _ in
    print("Dummy changed")
})

dummy.name = "Foo"              // Will trigger
dummy.objectWillChange.send()   // Will trigger
Run Code Online (Sandbox Code Playgroud)

NSManagedObject 被窃听了吗?我应该如何观察通用实体对象的变化?我应该如何让 SwiftUI 看到它们?

这是使用 Xcode 11.0 和 iOS 13。

Ant*_*ony 8

我相信这是一个错误。没有必要NSManagedObject符合ObservableObject但无法将任何属性标记为@Published

在我们等待 Apple 纠正此问题的同时,我遇到了比 @jesseSpencer 建议的更简洁的解决方案。背后的逻辑是相同的,通过添加 a objectWillChange.send(),但全局添加到willChangeValue(forKey key: String)而不是添加到单个属性。

override public func willChangeValue(forKey key: String) {  
    super.willChangeValue(forKey: key)  
    self.objectWillChange.send()  
}
Run Code Online (Sandbox Code Playgroud)

学分:https : //forums.developer.apple.com/thread/121897


jes*_*cer 5

我的猜测是这是一个错误。NSManagedObject 与 ObservableObject 的一致性是在 beta 5 中添加的,它还引入了其他重大更改,包括弃用 BindableObject(由 ObservableObject 替换)。

请参阅 SwiftUI 部分:https : //developer.apple.com/documentation/ios_ipados_release_notes/ios_13_release_notes

我遇到了同样的问题,尽管 NSManagedObject 符合 ObservableObject,但它没有发出更改通知。这可能与需要用 @NSManaged 包装的 NSManagedObject 属性有关,@NSManaged 不能与 @Published 结合使用,而 ObservableObject 文档指出,默认情况下,ObservableObject 将为 @Published 属性更改合成 objectWillChange 发布者。https://developer.apple.com/documentation/combine/observableobject

我首先尝试通过引导调用对objectWillChange.send()我的 NSManagedObject 子类中的键值方法的覆盖调用来解决这个问题,这只会导致错误的行为。

如果您需要更改 SwiftUI 视图中的许多相互依赖的属性,我采用的解决方案是最简单但不幸的是可能是最笨重的。但是,到目前为止,它对我来说运行良好,并按预期保持使用 SwiftUI。


在斯威夫特:

  1. 为您的实体创建一个 NSManagedObject 子类。
  2. 在该子类中,为您希望从 SwiftUI 视图更改的属性创建 setter 方法,并在该方法的开头添加对 的调用objectWillChange.send(),该调用应如下所示:

    func setTitle(_ text: String) {
        objectWillChange.send()
    
        self.title = text
    }
    
    Run Code Online (Sandbox Code Playgroud)

我只建议这是一个临时的解决方法,因为它并不理想,希望很快会得到解决。

我将在 FeedbackAssistant 中提交错误报告,并建议遇到此问题的其他任何人也这样做,以便我们可以让 Apple 再看看这个!

编辑:关于@Anthony 答案的警告:虽然建议的方法确实有效,但请注意它在更改集合类型关系时将不起作用,即将对象添加到与 NSManagedObject 关联的数组中。