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

使用.receive(on:)能否保证.sink()执行时@Published属性已完成更新?

核心结论

添加receive(on:)无法从@Published的触发机制上保证.sink()闭包一定在属性值完成更新(didSet执行完毕)后执行,但在大多数主队列调度的场景下,会因为异步调度的特性,让闭包在赋值流程完成后运行——这是调度顺序带来的巧合,而非@Published触发逻辑的改变。


为什么默认.sink()会拿到旧值

@Published的底层实现是在属性的willSet阶段发送新值通知,执行顺序如下:

  • 给@Published属性赋值时,先进入willSet,此时属性的实际值仍是旧值,新值尚未写入
  • @Published在willSet里向下游发送通知,触发.sink()闭包同步执行
  • 等.sink()闭包执行完成,才会完成属性的新值写入,再执行didSet

所以默认情况下,.sink()闭包执行时,直接访问属性本身拿到的还是旧值——这也是示例中不加receive(on:)时表格无法刷新新数据的原因:闭包执行时viewModel.dataSource还没更新。


receive(on:)的实际作用

receive(on:)的唯一作用是指定.sink()闭包在哪个调度器上执行。比如示例中指定RunLoop.main,相当于把闭包的执行异步推迟到当前队列的下一个循环周期。

而属性的整个赋值流程(包括willSet发通知、写入新值、执行didSet)是在当前同步流程里完成的,所以异步调度的.sink()闭包会等整个赋值流程走完才会运行——此时闭包访问属性时,新值已经写入,didSet也执行完毕,表格就能正确刷新。

但要明确:这只是调度顺序带来的结果,@Published依然在willSet阶段发送通知,并没有改变触发逻辑。


为什么它不是“根本解决方案”

这种依赖调度顺序的做法存在失效场景:

  • 如果receive(on:)指定的是并行调度器(比如全局后台队列),而属性赋值在另一个队列执行,.sink()闭包可能和属性的didSet并行运行,此时访问属性可能仍拿不到新值
  • 如果当前队列被长时间同步任务阻塞,异步推迟的.sink()闭包会被延迟执行,但这属于队列阻塞问题,而非属性更新机制的问题

如果要从机制上保证.sink()在属性完成更新后执行,更可靠的方式是:

  • 直接使用.sink()闭包的receiveValue参数(这个参数就是willSet里的新值,无需依赖属性本身的状态)
  • 放弃@Published的自动通知,在属性的didSet里手动用自定义PassthroughSubject或CurrentValueSubject发送通知

示例代码对比

不添加receive(on:)时,闭包执行时属性未更新:

override func viewDidLoad()
{
    super.viewDidLoad()

    viewModel.$dataSource
        .sink(receiveValue: { [weak self] _ in
            // 此时viewModel.dataSource仍是旧值
            self?.tableView.reloadData() // 刷新旧数据
        })
} 

@IBAction func addItems()
{
    viewModel.dataSource = ["One", "Two", "Three"]
}

添加receive(on: RunLoop.main)后,闭包异步执行时属性已更新:

override func viewDidLoad()
{
    super.viewDidLoad()

    viewModel.$dataSource
        .receive(on: RunLoop.main)
        .sink(receiveValue: { [weak self] _ in
            // 此时viewModel.dataSource已完成赋值,didSet执行完毕
            self?.tableView.reloadData() // 刷新新数据
        })
} 

@IBAction func addItems()
{
    viewModel.dataSource = ["One", "Two", "Three"]
}

内容的提问来源于Stack Exchange,提问作者meaning-matters

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 18:21:34