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

SwiftUI多层@Published嵌套未触发更新,Text颜色无法实时变化

问题根源

SwiftUI 的 @Published 对引用类型的监听逻辑是:只有当属性的引用地址发生变化时,才会向外发送更新通知。你当前的嵌套结构全为类(引用类型),因此深层 ECAMDoor 中的 doorarray 发生变化时,外层的 GameManager、MakeCockpit、ECAMManager 都不会自动转发该更新事件,视图无法收到刷新信号,只有重新打开视图触发重绘时才会加载最新数据。

解决方案

方案1:手动转发嵌套对象的变更通知(改动最小)

在每一层父级可观察对象中,监听子级的 objectWillChange 事件,向上转发到父级的更新通知流即可。
注:该方案需要导入Combine框架,在对应文件头部添加import Combine即可

调整 GameManager 代码:

class GameManager: NSObject, ObservableObject, ARSessionDelegate, ARSCNViewDelegate {
    @Published var cockpit = MakeCockpit()
    private var cancellables = Set<AnyCancellable>()

    override init() {
        super.init()
        // 转发 cockpit 的变更通知
        cockpit.objectWillChange
            .receive(on: DispatchQueue.main)
            .sink { [weak self] _ in
                self?.objectWillChange.send()
            }
            .store(in: &cancellables)
    }
    // 其余原有逻辑
}

调整 MakeCockpit 代码:

class MakeCockpit: SCNNode, ObservableObject {
    @Published var ecamManager = ECAMManager()
    private var cancellables = Set<AnyCancellable>()

    override init() {
        super.init()
        // 转发 ecamManager 的变更通知
        ecamManager.objectWillChange
            .receive(on: DispatchQueue.main)
            .sink { [weak self] _ in
                self?.objectWillChange.send()
            }
            .store(in: &cancellables)
    }
    // 其余原有逻辑
}

调整 ECAMManager 代码:

class ECAMManager: ObservableObject {
    @Published var door = ECAMDoor()
    @Published var stanby = ECAMsby()  
    private var cancellables = Set<AnyCancellable>()

    init() {
        // 转发 door 的变更通知
        door.objectWillChange
            .receive(on: DispatchQueue.main)
            .sink { [weak self] _ in
                self?.objectWillChange.send()
            }
            .store(in: &cancellables)
        // 转发 stanby 的变更通知
        stanby.objectWillChange
            .receive(on: DispatchQueue.main)
            .sink { [weak self] _ in
                self?.objectWillChange.send()
            }
            .store(in: &cancellables)
    }
    // 其余原有逻辑
}

方案2:将数据层改为结构体(更符合SwiftUI设计理念)

如果业务场景不需要引用类型的特性,可以把 Door、ECAMDoor、ECAMManager、MakeCockpit 这些数据承载类改为结构体(值类型),这样任意深层属性变化都会被外层的 @Published 感知到,无需手动转发通知,逻辑更简洁。

方案3:拆分视图层级,子视图单独监听深层对象

把需要用到 doorarray 的部分抽成单独的子视图,直接把 doorarray 所属的 ECAMDoor 实例作为参数传入子视图,用 @ObservedObject 修饰,即可直接监听到变化,不需要修改父级的转发逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 03:45:05