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

修改ObservedObject嵌套属性时通知不触发的原因及解决方法咨询

问题原因

ObservableObject 协议的默认自动通知机制,以及 @Published 属性包装器的触发逻辑,都仅在被修饰的属性本身发生赋值操作时才会生效:

  • 你代码中的 Stuff 是引用类型(class),MyStuff 中 @Published 修饰的 stuff 属性实际存储的是 Stuff 实例的内存地址
  • 当你修改 stuff?.str、stuff?.num 这类嵌套属性时,stuff 本身的内存地址没有发生变化,相当于没有对 stuff 做赋值操作,因此 @Published 不会触发通知,上层的订阅自然不会回调。
解决方案

下面是三种常用的实现方案,按优先级从高到低排序:

  • 方案1:将 Stuff 改为值类型(struct)【优先推荐】
    值类型的特点是只要内部属性发生修改,整个实例的值就会发生变化,触发外层 @Published 的赋值检测,自动发送通知。修改后代码如下:
// 把class改成struct即可
struct Stuff {
    var str: String?
    var num = 0
}

// 其余MyStuff、DoSomething的代码不需要改动

修改嵌套属性时就会自动触发所有订阅回调。

  • 方案2:Stuff 必须保留为class的场景,手动桥接通知
    让 Stuff 也遵守 ObservableObject 协议,内部属性添加 @Published 修饰,同时在 MyStuff 中监听 stuff 的变化,转发通知到外层:
import Combine

class Stuff: ObservableObject {
    @Published var str: String?
    @Published var num = 0
}

class MyStuff:ObservableObject {
    @Published var stuff:Stuff?
    @Published var numer: Int?
    private var cancellableBag = Set<AnyCancellable>()
    
    init() {
        // 监听stuff的objectWillChange,转发到当前实例的objectWillChange
        $stuff
            .compactMap { $0?.objectWillChange }
            .switchToLatest()
            .sink(receiveValue: { [weak self] _ in
                self?.objectWillChange.send()
            })
            .store(in: &cancellableBag)
    }
}

// DoSomething代码无需改动
  • 方案3:临时手动触发通知【仅应急使用,不推荐】
    每次修改 Stuff 嵌套属性之后,手动调用 objectWillChange 发送通知:
let doSomething = DoSomething()
// 修改前手动发通知
doSomething.observedObject.objectWillChange.send()
doSomething.observedObject.stuff?.str = "Doing something"
doSomething.observedObject.stuff?.num = 2

该方案容易遗漏调用,后续维护成本高,仅适合临时调试或极少修改的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 22:39:03