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

为何ObservableObject结合Timer无法更新SwiftUI View?求技术解释

问题:ObservableObject内部通过Timer更新数据时,StateObject无法刷新Text视图

我正在尝试理解为何在ObservableObject内部通过Timer更新数据时,StateObject无法刷新我的Text视图,恳请各位提供相关解释。

相关代码

视图代码

struct DailyNotificaitonView: View {
    @StateObject var x = Test2()
    
    var body: some View {
        VStack {
            Text("\(x.progress.x)")
                .onAppear {
                    Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
                        DispatchQueue.main.async {
                            print(x.progress.x)
                        }
                    } 
              }
        }
    }
}

ObservableObject代码

class Test2: ObservableObject {
    @ObservedObject var progress = Test()
    
    init() {
        Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
            DispatchQueue.main.async {
                self.update()
            }
        }
    }
    
    func update() {
        print("updated")
        progress.x += 1
        progress.y += 1
    }
}

class Test: ObservableObject {
    @Published var x: Int = 0 {
        willSet {
            objectWillChange.send()
        }
    }
    @Published var y: Int = 0
}

问题原因及解决方案

核心问题

  1. Test2中错误使用@ObservedObject:@ObservedObject是SwiftUI View专属的属性包装器,用于在视图层监听ObservableObject的变化。但在ObservableObject类内部(比如Test2),它无法将内部子对象(progress)的属性变化传递给外部视图。当progress的属性更新时,Test2不会触发objectWillChange事件,导致视图感知不到数据变化,自然不会刷新Text。

  2. Test中多余的手动事件发送:@Published属性会自动在值变更时发送objectWillChange事件,所以x属性的willSet里手动调用objectWillChange.send()完全冗余,甚至可能引发重复通知。

修复方案

  • 将Test2中的@ObservedObject var progress = Test()改为@Published var progress = Test():@Published会监听progress对象的内部变化,当progress的@Published属性更新时,Test2会自动发送objectWillChange事件,通知视图刷新。
  • 移除Test中x属性的willSet手动发送逻辑。

修复后的代码:

class Test2: ObservableObject {
    @Published var progress = Test() // 替换为@Published
    
    init() {
        Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
            DispatchQueue.main.async {
                self.update()
            }
        }
    }
    
    func update() {
        print("updated")
        progress.x += 1
        progress.y += 1
    }
}

class Test: ObservableObject {
    @Published var x: Int = 0 // 移除多余的willSet逻辑
    @Published var y: Int = 0
}

注:视图中onAppear内的Timer仅用于打印值,不影响视图刷新逻辑,可根据需求保留或删除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:24:27