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

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 中监听内部存储对象的变更,手动触发自身的更新通知:

  1. 导入 Combine 框架
  2. 新增订阅存储集,在初始化时添加监听:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:24:07