SwiftUI视图未响应EnvironmentObject中Observable属性更新(Firestore场景)
问题根因
SwiftUI 的 ObservableObject 体系中,@Published 仅对值类型的属性变更生效,或是对引用类型的属性整体替换时生效。你当前的结构存在层级观察失效的问题:
SignedInAuthentication是你注入的环境对象,它的workoutCompletionStore是引用类型的类实例- 当
WorkoutCompletionDataStore内部的workoutCompletions变更时,SignedInAuthentication持有的workoutCompletionStore指针本身没有变化,所以SignedInAuthentication不会触发视图更新通知,Home 页面自然不会刷新。
解决方案
方案1(最推荐):把数据存储单独作为环境对象注入
直接将 WorkoutCompletionDataStore 实例单独通过 .environmentObject() 注入到视图层级,在 HomeScreen 中直接声明:
@EnvironmentObject var workoutCompletionStore: WorkoutCompletionDataStore
它自身是 ObservableObject,内部 @Published 属性变更时会直接触发视图刷新。
方案2:在 SignedInAuthentication 中手动转发变更通知
如果你需要保留当前的封装结构,需要在 SignedInAuthentication 中监听内部存储对象的变更,手动触发自身的更新通知:
- 导入 Combine 框架
- 新增订阅存储集,在初始化时添加监听:
import Combine class SignedInAuthentication: ObservableObject { @Published var user: User @Published var workoutCompletionStore: WorkoutCompletionDataStoreProtocol // 存储订阅 private var cancellables = Set<AnyCancellable>() init(user: User, workoutCompletionStore: WorkoutCompletionDataStoreProtocol) { self.user = user self.workoutCompletionStore = workoutCompletionStore // 监听存储对象的变更,转发到当前类的更新通知 workoutCompletionStore.objectWillChange .receive(on: DispatchQueue.main) .sink { [weak self] _ in self?.objectWillChange.send() } .store(in: &cancellables) } init(user: User) { self.user = user let store = WorkoutCompletionDataStore(userId: user.userId) self.workoutCompletionStore = store // 同样添加监听逻辑 store.objectWillChange .receive(on: DispatchQueue.main) .sink { [weak self] _ in self?.objectWillChange.send() } .store(in: &cancellables) } }
注意:需要确保 WorkoutCompletionDataStoreProtocol 继承了 ObservableObject 协议,才能访问 objectWillChange 属性
方案3:在视图层单独声明存储对象为观察对象
在 HomeScreen 中直接把嵌套的存储对象声明为 @ObservedObject:
struct HomeScreen: View { @ObservedObject var homeQueryData: HomeQueryData @AppStorage("didShowOnboarding") var didShowOnboarding: Bool = false @EnvironmentObject var signedInAuthentication: SignedInAuthentication // 单独观察内部的存储对象 @ObservedObject private var workoutCompletionStore: WorkoutCompletionDataStore init(homeQueryData: HomeQueryData) { self.homeQueryData = homeQueryData // 从环境对象中取出存储对象赋值给观察属性 self._workoutCompletionStore = ObservedObject(initialValue: signedInAuthentication.workoutCompletionStore as! WorkoutCompletionDataStore) } // 后续 body 直接使用 workoutCompletionStore.workoutCompletions 即可 }
内容的提问来源于stack exchange,提问作者otusweb
相关产品推荐
相关产品推荐

