SwiftUI MVVM下如何为作为EnvironmentObject的ViewModel注入其他环境对象
问题根源
@EnvironmentObject 是 SwiftUI 专门为视图组件提供的属性包装器,仅在视图的生命周期内生效,无法作用于普通的 ObservableObject 类型的 ViewModel 类,所以你在 ViewModel 中加这个修饰器是完全无效的,自然会抛出找不到实例的崩溃。
解决方案
通过构造器注入的方式传递依赖即可,不需要把过滤逻辑移到View层:
1. 修改 OfferHistoryViewModel 定义
删掉无效的 @EnvironmentObject 修饰,改为普通存储属性,同时调整构造器参数,优化Combine逻辑同时监听用户状态和仓库数据变化:
import Combine class OfferHistoryViewModel: ObservableObject { // MARK: Properties let authSession: AuthSession let offerRepository: OfferRepository @Published var offerRowViewModels = [OfferRowViewModel]() private var cancellables = Set<AnyCancellable>() // MARK: Initializer init(offerRepository: OfferRepository, authSession: AuthSession) { self.offerRepository = offerRepository self.authSession = authSession self.startCombine() } // MARK: Combine Logic func startCombine() { // 同时监听仓库offer变化和用户ID变化,任意一个更新都会重新过滤数据 Publishers.CombineLatest( offerRepository.$offers, authSession.$currentUserUid ) .receive(on: RunLoop.main) .map { offers, currentUid in offers .filter { $0.userId == currentUid } .map { OfferRowViewModel(offer: $0) } } .assign(to: \.offerRowViewModels, on: self) .store(in: &cancellables) } }
2. 修改App入口的初始化逻辑
创建OfferHistoryViewModel时直接传入已经初始化好的AuthSession实例:
@main struct The_ExchangeApp: App { @StateObject private var authListener = AuthSession() // 构造时直接注入依赖 @StateObject private var offerHistoryViewModel = OfferHistoryViewModel( offerRepository: OfferRepository(), authSession: authListener ) var body: some Scene { WindowGroup { ContentView() .environmentObject(authListener) .environmentObject(offerHistoryViewModel) } } }
该方案符合MVVM架构规范:业务过滤逻辑保留在ViewModel层,View只需要负责渲染offerRowViewModels即可,同时保证了用户登录状态切换时列表会自动刷新,不需要额外手动处理。
内容的提问来源于stack exchange,提问作者jonthornham
相关产品推荐
相关产品推荐

