Combine Swift中声明初始值后Sink.receive()未触发的问题
问题原因与修复方案
问题原因
objectWillChange是ObservableObject提供的内置Publisher,它仅发送Void类型的事件,作用是通知监听者“对象即将发生变化”,并不会传递具体的属性值,所以打印value会输出()。hasBirthday()方法没有定义返回值,默认返回Void类型,将它赋值给hasBirthday常量后,打印该常量自然会输出()。- 你期望获取
age属性的具体数值变化,但当前代码监听的是对象的整体变化通知,而非age属性对应的Publisher,因此无法拿到30、31这些目标数值。
修复方案
要实现“先输出30,再输出31”的需求,需要订阅age属性对应的@Published Publisher,同时调整代码中无意义的变量赋值:
修复后的完整代码
import Combine class Contact: ObservableObject { @Published var name: String @Published var age: Int init(name: String, age: Int) { self.name = name self.age = age } func hasBirthday() { age += 1 } } var cancellable: AnyCancellable! let asaad = Contact(name: "Asaad Jaber", age: 30) // 订阅age属性的Publisher,会自动发送初始值和后续变化值 cancellable = asaad.$age .sink(receiveValue: { ageValue in print("received value \(ageValue)") }) // 直接调用方法,无需赋值(方法无返回值) asaad.hasBirthday() print("asaad has birthday")
关键修改点说明
- 替换监听对象:用
asaad.$age替代asaad.objectWillChange。$age是@Published属性自动生成的Publisher,会主动发送该属性的当前值和所有后续更新值,因此订阅后会先输出初始值30,调用hasBirthday()后输出更新后的31。 - 移除无意义赋值:
hasBirthday()没有返回值,直接调用即可,不需要将其赋值给变量,避免打印出()。
补充场景说明
如果确实需要监听对象任意属性的变化(而非单个属性),可以继续使用objectWillChange,但要获取属性值需要手动读取:
cancellable = asaad.objectWillChange .sink(receiveValue: { _ in // 这里读取的是变化前的属性值,若要获取变化后的值,建议结合`receive(on:)`或直接订阅对应属性的Publisher print("object will change, current age: \(asaad.age)") })
不过这种方式无法直接拿到变化后的新值,因此针对需要获取具体属性数值的场景,优先使用对应属性的$xxx Publisher。
内容的提问来源于stack exchange,提问作者Asaad Jaber
相关产品推荐
相关产品推荐

