为何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 }
问题原因及解决方案
核心问题
Test2中错误使用@ObservedObject:@ObservedObject是SwiftUI View专属的属性包装器,用于在视图层监听ObservableObject的变化。但在ObservableObject类内部(比如Test2),它无法将内部子对象(progress)的属性变化传递给外部视图。当progress的属性更新时,Test2不会触发objectWillChange事件,导致视图感知不到数据变化,自然不会刷新Text。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
相关产品推荐
相关产品推荐

