SwiftUI中如何观察@State修饰的Int类型变量的变化?
SwiftUI 变量更新异常问题解答
根因分析
@State属性包装器的设计作用域为 SwiftUI 视图渲染周期,它的底层存储由 SwiftUI 运行时托管,只有在视图的body执行上下文中修改才会触发视图刷新。- 你在
App结构体的init方法中直接调用fetchNewTest()时,SwiftUI 还未完成对@State var test的存储绑定,此时修改test实际操作的是值类型结构体的临时副本,修改不会被同步到运行时,后续递归触发的定时修改也无法触发视图更新。
解决方案
方案1:使用@StateObject托管全局状态(更推荐)
使用引用类型的可观察对象管理可变状态,从根本上避免值类型的临时副本问题:
import SwiftUI class TestStateManager: ObservableObject { @Published var test: Int = 0 func fetchNewTest() { test = test == 0 ? 1 : 0 DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in guard let self = self else { return } self.fetchNewTest() } } } @main struct TestSwiftUIApp: App { @StateObject private var stateManager = TestStateManager() var body: some Scene { WindowGroup { ContentView(value: $stateManager.test) .onAppear { stateManager.fetchNewTest() } } } } struct ContentView: View { @Binding var value: Int var body: some View { Text("\(value)") .padding() } }
@Published修饰的属性变更会自动通知订阅的视图刷新,onAppear回调触发时,SwiftUI 已经完成所有状态的初始化绑定,此时启动定时逻辑可以正常生效。
方案2:最小改动适配原代码
如果不想额外创建状态管理类,只需要把fetchNewTest()的调用从init移到视图的onAppear回调中即可:
@main struct TestSwiftUIApp: App { @State var test: Int = 0 var body: some Scene { WindowGroup { ContentView(value: $test) .onAppear { fetchNewTest() } } } func fetchNewTest() { test = test == 0 ? 1 : 0 DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in guard let self = self else { return } self.fetchNewTest() } } } struct ContentView: View { @Binding var value: Int var body: some View { Text("\(value)") .padding() } }
内容的提问来源于stack exchange,提问作者Kelton
相关产品推荐
相关产品推荐

