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

@Published发布时机、.onReceive执行条件及变更检测原理问询

关于@Published和.onReceive的机制详解

好的,咱们一个个来拆解你的问题,结合SwiftUI和Combine的底层逻辑给你讲明白:

1. @Published何时发布它包装的值?

@Published是Combine框架提供的属性包装器,它的发布时机完全取决于你包装的类型是值类型(struct/enum)还是引用类型(class):

  • 值类型场景:每当属性的「整个值」发生变化时(包括修改内部属性,因为值类型是值语义,修改内部属性相当于生成了一个全新的实例),@Published会自动发布新值。比如如果Feed是struct,你执行feedData.personalTasks.append(...),这会触发feedData的setter,@Published就会发送通知。
  • 引用类型场景:只有当你给这个属性赋值一个新的实例时(比如feedData = Feed()),@Published才会发布。如果只是修改现有实例的内部属性(比如feedData.personalTasks.append(...)),因为引用类型的实例指针没变化,@Published的setter不会被触发,自然不会发布新值。

2. 你的代码中.onReceive何时会被执行?

.onReceive(feed.$feedData)本质是订阅feed.$feedData这个Publisher的数据流,只有当这个Publisher发布新值的时候,闭包才会执行:

  • 如果Feed是值类型:每次feedData的任意内部属性变化(比如personalTasks添加元素),都会触发@Published发布新值,进而执行你的.onReceive闭包,检查personalTasks.count并更新showCards。
  • 如果Feed是引用类型:只有当你把feedData替换成一个全新的Feed实例时,.onReceive才会被执行。单纯修改personalTasks的内容,不会触发这个闭包。

3. @Published如何感知feedData内部的变化?

@Published的核心实现是利用属性的didSet观察者:

  • 当你给被@Published包装的属性赋值时(也就是setter被调用),它会在didSet里把新值发送给所有订阅者。
  • 对于值类型来说,修改内部属性会触发整个值的重新赋值(值语义的特性),所以setter会被调用,didSet触发,@Published就能感知到变化并发布。
  • 对于引用类型,修改内部属性不会触发属性本身的setter(因为实例的引用地址没变),所以@Published无法自动感知。如果想让引用类型的内部变化也能触发通知,你需要让Feed类本身遵循ObservableObject,并用@Published标记它的personalTasks属性,然后在父对象里订阅feedData.$personalTasks的变化,或者用Combine的merge等操作符合并多个Publisher的数据流。

内容的提问来源于stack exchange,提问作者belotserkovtsev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 14:27:47