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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:33:03