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

SwiftUI多层嵌套Published对象变更时视图未响应更新的问题求助

问题分析

这不是SwiftUI的bug,而是因为ObservedObject只会监听第一层@Published属性的引用变化:当你修改嵌套对象(RecordingTimeManager)内部的@Published属性时,外层的AppStatus并没有发出对象变化的通知,所以SwiftUI视图不会重新渲染。

具体来说,你的AppStatus里的recordingTimeManager是一个@Published对象,但只有当你把它替换成一个新的RecordingTimeManager实例时,AppStatus的objectWillChange才会触发。而你只是修改了现有实例内部的maxRecordingTime,外层的AppStatus不会感知到这个变化,自然不会更新视图。另外你的代码里还有个小疏漏:RecordingTimeManager没有遵循ObservableObject协议,这是内部@Published属性生效的前提。

解决方案

这里提供两种可行的解决方式,你可以根据项目结构选择:

方案1:让嵌套对象的变化传递到外层ObservableObject

先给RecordingTimeManager补上ObservableObject协议,再在AppStatus中订阅嵌套对象的变化事件,手动触发自身的更新通知:

// 修正RecordingTimeManager,添加ObservableObject协议
class RecordingTimeManager: ObservableObject {
    @Published var maxRecordingTime: TimeSeletedTime = .sixteenSeconds
    // ...其他代码
}

// 修改AppStatus,传递嵌套对象的变化通知
class AppStatus: ObservableObject {
    @Published var recordingTimeManager: RecordingTimeManager = RecordingTimeManager()
    private var cancellables = Set<AnyCancellable>()

    init() {
        // 当recordingTimeManager内部属性变化时,触发AppStatus的对象更新
        recordingTimeManager.objectWillChange
            .sink { [weak self] _ in
                self?.objectWillChange.send()
            }
            .store(in: &cancellables)
    }
}

这样修改后,当你更新maxRecordingTime时,RecordingTimeManager的变化会传递给AppStatus,最终触发SwiftUI视图重新渲染,按钮的前景色就能正常更新了。

方案2:在视图中直接监听嵌套对象

如果你不想改动AppStatus的结构,可以在SwiftUI视图里把recordingTimeManager单独作为ObservedObject来监听:

struct YourRecordingView: View {
    @ObservedObject var appStatus: AppStatus
    // 单独监听嵌套的RecordingTimeManager
    @ObservedObject var timeManager: RecordingTimeManager

    init(appStatus: AppStatus) {
        self.appStatus = appStatus
        self.timeManager = appStatus.recordingTimeManager
    }

    var body: some View {
        Button {
            timeManager.maxRecordingTime = .fifteenSeconds
            print("15 \(timeManager.maxRecordingTime)")
        } label: {
            Text("15")
                .font(Font.custom("BwGradual-Bold", size: 15))
                .foregroundColor(timeManager.maxRecordingTime == .fifteenSeconds ? CLAPSOFFWHITE : TRIBESGREY)
        }
    }
}

这种方式让视图直接绑定到RecordingTimeManager的变化,当内部属性更新时,视图会自动重新渲染。

注意事项
  • 所有包含@Published属性的类必须遵循ObservableObject协议,否则@Published不会生效。
  • 方案1中使用Combine的sink时,一定要用[weak self]避免循环引用,同时用cancellables存储订阅者,防止订阅被提前释放。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:04:06