更改 ObservedObject 时未发送通知
Notifications not sent when changing an ObservedObject
我有以下代码:
class Stuff {
var str: String?
var num = 0
}
class MyStuff:ObservableObject {
@Published var stuff:Stuff?
@Published var numer: Int?
}
class DoSomething {
let observedObject = MyStuff()
var cancellableBag = Set<AnyCancellable>()
init() {
observedObject.objectWillChange.sink { value in
print(value)
print("Object has changed")
}.store(in: &cancellableBag)
observedObject.$stuff.sink { value in
print(value?.str ?? "")
}.store(in: &cancellableBag )
}
}
但是当我执行时:
let doSomething = DoSomething()
doSomething.observedObject.stuff?.str = "Doing something"
doSomething.observedObject.stuff?.num = 2
,通知永远不会触发:
你们知道为什么通知永远不会触发吗?或者我怎样才能实现它?
问题是doSomething.observedObject.stuff
它是零。
我修复了:
let doSomething = DoSomething()
let stuff = Stuff()
stuff.str = "Doig Something"
doSomething.observedObject.stuff = stuff
正如评论中已经建议的那样,如果要使其工作,则需要将 class 转换为结构:struct Stuff {
。结构是一种值类型,这使得它可以很好地与 ObservableObject
一起使用,而 class 是一种引用类型,但它不能很好地工作。
@Published
属性需要是“纯”值类型,如果你想在它们的内容发生变化时得到通知。 “纯”是指仅由其他值类型构成的值类型,这些值类型也是“纯”的。
为什么需要这个?这是因为 @Published
机制依赖于 willSet
/didSet
属性 观察者,而 属性 观察者只有在持有的值发生变化时才会执行。
对于值类型,其结构中的任何更改都会向上游传播,从而导致整个 属性 被更新。这是由于值类型的语义造成的。
查看此代码片段:
struct Question {
var title: String = ""
}
class Page {
var question = Question() {
didSet {
print("Question changed: \(question)")
}
}
}
let page = Page()
page.question.title = "@Published doesn't work"
对 question
成员的任何更改都会导致整个 属性 被替换,这会触发 willSet
/didSet
属性 观察者,因此您可以很好地监控 question
.
的数据结构的任何变化
然而,上述内容不适用于 classes。 类 有身份,它们有一个固定的内存位置,不像值类型,它在使用时会被复制到各处。这意味着它们内部结构的变化不会反映在上游,因为 class 实例存储不会改变。
唯一一次 @Published
观察器被触发 classes 是在您替换对象本身时。试试这个,你会看到通知被触发:
doSomething.observedObject.stuff = Stuff() // this will print `Object has changed`
我有以下代码:
class Stuff {
var str: String?
var num = 0
}
class MyStuff:ObservableObject {
@Published var stuff:Stuff?
@Published var numer: Int?
}
class DoSomething {
let observedObject = MyStuff()
var cancellableBag = Set<AnyCancellable>()
init() {
observedObject.objectWillChange.sink { value in
print(value)
print("Object has changed")
}.store(in: &cancellableBag)
observedObject.$stuff.sink { value in
print(value?.str ?? "")
}.store(in: &cancellableBag )
}
}
但是当我执行时:
let doSomething = DoSomething()
doSomething.observedObject.stuff?.str = "Doing something"
doSomething.observedObject.stuff?.num = 2
,通知永远不会触发:
你们知道为什么通知永远不会触发吗?或者我怎样才能实现它?
问题是doSomething.observedObject.stuff
它是零。
我修复了:
let doSomething = DoSomething()
let stuff = Stuff()
stuff.str = "Doig Something"
doSomething.observedObject.stuff = stuff
正如评论中已经建议的那样,如果要使其工作,则需要将 class 转换为结构:struct Stuff {
。结构是一种值类型,这使得它可以很好地与 ObservableObject
一起使用,而 class 是一种引用类型,但它不能很好地工作。
@Published
属性需要是“纯”值类型,如果你想在它们的内容发生变化时得到通知。 “纯”是指仅由其他值类型构成的值类型,这些值类型也是“纯”的。
为什么需要这个?这是因为 @Published
机制依赖于 willSet
/didSet
属性 观察者,而 属性 观察者只有在持有的值发生变化时才会执行。
对于值类型,其结构中的任何更改都会向上游传播,从而导致整个 属性 被更新。这是由于值类型的语义造成的。
查看此代码片段:
struct Question {
var title: String = ""
}
class Page {
var question = Question() {
didSet {
print("Question changed: \(question)")
}
}
}
let page = Page()
page.question.title = "@Published doesn't work"
对 question
成员的任何更改都会导致整个 属性 被替换,这会触发 willSet
/didSet
属性 观察者,因此您可以很好地监控 question
.
然而,上述内容不适用于 classes。 类 有身份,它们有一个固定的内存位置,不像值类型,它在使用时会被复制到各处。这意味着它们内部结构的变化不会反映在上游,因为 class 实例存储不会改变。
唯一一次 @Published
观察器被触发 classes 是在您替换对象本身时。试试这个,你会看到通知被触发:
doSomething.observedObject.stuff = Stuff() // this will print `Object has changed`