You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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")

关键修改点说明

  1. 替换监听对象:用asaad.$age替代asaad.objectWillChange。$age是@Published属性自动生成的Publisher,会主动发送该属性的当前值和所有后续更新值,因此订阅后会先输出初始值30,调用hasBirthday()后输出更新后的31。
  2. 移除无意义赋值: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:20:16