为何在View2修改authState时,View1的onChange(of:)未触发?
问题原因分析
你遇到的问题核心在于视图的生命周期管理:
MainTabView通过ZStack+switch切换页面时,当选中View2,View1会被直接从视图树中移除并销毁;切回View1时,View1是全新创建的实例。这种情况下:
- 在View2中修改
authState后,切回View1时,新的View1实例初始化时拿到的就是修改后的authState值,而onChange(of:)仅监听当前视图实例生命周期内的属性变化,自然不会触发回调。
解决方案
方案一:保留View1的存活状态
通过透明度和可点击性控制视图显示,让View1和View2始终存在于视图树中,避免被销毁:
struct MainTabView: View { @State private var selectedTab = 0 var body: some View { ZStack { View1() .opacity(selectedTab == 0 ? 1 : 0) .allowsHitTesting(selectedTab == 0) View2() .opacity(selectedTab == 1 ? 1 : 0) .allowsHitTesting(selectedTab == 1) } .safeAreaInset(edge: .bottom) { HStack { Button("1") { selectedTab = 0 } Button("2") { selectedTab = 1 } } .buttonStyle(.borderedProminent) } } }
这种方式下,View1始终存活,当authState变化时,onChange(of:)会正常触发。
方案二:在视图初始化时订阅状态变化
利用Task订阅authState的数据流,即使View1被重建,也能在视图出现时监听后续的状态变化:
struct View1: View { @Environment(AuthManager.self) var authManager var body: some View { NavigationStack { VStack { Text("\(authManager.authState)") } .task { // 订阅authState的所有变化 for await _ in authManager.$authState.values { print("Changed") } } } } }
如果需要在视图出现时立即检查一次状态,可以在task开头先执行一次逻辑:
.task { print("Current state: \(authManager.authState)") for await _ in authManager.$authState.values { print("Changed") } }
方案三:在AuthManager层面添加状态回调
通过在AuthManager中定义闭包,统一处理状态变化通知,避免依赖视图生命周期:
@Observable class AuthManager { var authState: AuthState = .signedOut { didSet { onAuthStateChange?(authState) } } // 定义状态变化回调 var onAuthStateChange: ((AuthState) -> Void)? // ...其他代码 }
然后在View1中绑定回调(注意弱引用避免内存泄漏):
struct View1: View { @Environment(AuthManager.self) var authManager var body: some View { NavigationStack { VStack { Text("\(authManager.authState)") } .onAppear { authManager.onAuthStateChange = { [weak self] _ in guard let self = self else { return } print("Changed") } } .onDisappear { authManager.onAuthStateChange = nil } } } }
内容的提问来源于stack exchange,提问作者mangobeach
相关产品推荐
相关产品推荐

