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
相关产品推荐
相关产品推荐

