NSManagedObject更改不会触发对象WillChange

50pmv0ei  于 2022-10-23  发布在  Swift
关注(0)|答案(3)|浏览(110)

我有一个核心数据模型,其中一个实体生成到类Task中。我正在尝试从NSManagedObject中获取要发送的联合发布者objectWillChange(自动发送,无需手动操作),但不会成功。任务实体具有name属性。

let task = Task(context: container.viewContext)

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

task.name = "Foo"              // WILL NOT trigger

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

task.objectWillChange.send()   // Will trigger

如果我将其替换为简单的ObservableObject,它将按预期工作:

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

dummy.name = "Foo"              // Will trigger
dummy.objectWillChange.send()   // Will trigger

NSManagedObject是否已被窃听?我应该如何观察常规实体对象的更改?我应该如何让SwiftUI看到它们?
这是使用Xcode11.0和iOS 13。

cbjzeqam

cbjzeqam1#

我相信这是一个虫子。NSManagedObject符合ObservableObject,但无法将任何属性标记为@Published,这是没有意义的。
在我们等待苹果纠正这一问题的同时,我发现了一个比@jesseSpencer建议的更干净的解决方案。背后的逻辑是相同的,通过添加objectWillChange.send(),但全局添加到willChangeValue(forKey key: String)中,而不是添加到单个属性中。

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

制片人:https://forums.developer.apple.com/thread/121897

jk9hmnmh

jk9hmnmh2#

我的猜测是,这是一个错误。NSManagedObject与ObservableObject的一致性是在Beta 5中添加的,它还引入了其他重大变化,包括不推荐使用BindableObject(替换为ObservableObject)。
请参阅SwiftUI部分:https://developer.apple.com/documentation/ios_ipados_release_notes/ios_13_release_notes)
我遇到了同样的问题,尽管NSManagedObject符合ObservableObject,但它没有发出更改通知。这可能与需要用@NSManaged Package 的NSManagedObject属性有关,但不能与@发布的属性组合,而ObservableObject文档声明,默认情况下,ObservableObject将合成@发布属性更改的objectWillChange发布者。https://developer.apple.com/documentation/combine/observableobject
我首先尝试通过引导对objectWillChange.send()的调用来覆盖我的NSManagedObject子类中的键值方法,从而尝试解决这个问题,这只会导致不正确的行为。
如果您需要在SwiftUI视图中更改许多相互依赖的属性,我使用的解决方案是最简单的,但不幸的是,可能是最笨重的。但是,到目前为止,它对我来说运行得很好,并保持了对SwiftUI的预期使用。
在SWIFT:
1.为您的实体创建NSManagedObject子类。
1.在该子类中,为您希望从SwiftUI视图更改的属性创建setter方法,并在该方法的开头添加对objectWillChange.send()的调用,该调用应如下所示:

func setTitle(_ text: String) {
    objectWillChange.send()

    self.title = text
}

我只是建议这是一种临时的解决办法,因为这并不理想,希望很快就能解决。
我将在Feedback Assistant中提交一份错误报告,我建议遇到这个问题的其他人也这样做,这样我们就可以让Apple重新考虑这个问题!
编辑:关于@Anthony的回答的警告:虽然建议的方法确实有效,但请注意,当更改集合类型关系时,例如将对象添加到与NSManagedObject关联的数组中时,它将不起作用。

js81xvg6

js81xvg63#

要观察NSManagedObject的变化,请查看:https://developer.apple.com/documentation/combine/performing-key-value-observing-with-combine
请注意,当您在UICollectionViewListCellUITableViewCell自定义类中使用该方法时,您应该覆盖prepareForReuse方法并放入类似的代码:

override func prepareForReuse() {
   super.prepareForReuse()
   nameObserver?.cancel()
   nameObserver = nil
}

相关问题