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

SwiftUI环境对象报错求助:找不到ViewModel类型的ObservableObject

问题分析与解决

错误原因

  1. SwiftUI View是值类型:你调用rootView.environmentObject(HomeView.ViewModel())时,会返回一个新的View实例,而非修改原有的rootView。但传给super.init的仍是最初未注入环境对象的HomeView,导致HomeView渲染时找不到ViewModel实例,触发崩溃。
  2. 错误访问EnvironmentObject:试图通过rootView.viewModel直接读取环境对象,不符合SwiftUI设计——@EnvironmentObject实例由SwiftUI环境管理,外部不能通过View实例直接获取。

修复方案

核心思路

  • 初始化UIHostingController时,直接创建已注入environmentObject的HomeView实例
  • 在HomeViewController中持有ViewModel实例,后续更新属性直接操作该实例,而非通过View对象

修改后的代码

HomeViewController

class HomeViewController: UIHostingController<HomeView> {
    
    // MARK: - Public Properties
    var topThreePublicUsers = PassthroughSubject<[ExternalUser], Never>()

    // MARK: - Private Properties
    private var cancellables: Set<AnyCancellable> = []
    // 持有ViewModel实例,方便外部更新
    private let viewModel: HomeView.ViewModel
    
    // MARK: - Initializer
    init() {
        // 先创建ViewModel实例
        viewModel = HomeView.ViewModel()
        // 创建带有环境对象的rootView
        let rootView = HomeView().environmentObject(viewModel)
        super.init(rootView: rootView)

        topThreePublicUsers
            .receive(on: DispatchQueue.main)
            // 直接操作持有的viewModel实例
            .assign(to: \.topThreePublicUsers, on: viewModel)
            .store(in:&cancellables)
    }
    
    @MainActor required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func pushPublicLeaderBoard(viewController: UIViewController) {
        if let viewController = viewController as? UIHostingController<PublicLeaderboardView> {
            // 直接操作持有的viewModel实例
            viewModel.publicLeaderboard = viewController.rootView
        }
    }
}

HomeView(保持原结构,补充缺失属性)

struct HomeView: View {
    
    // MARK: - Environment
    @EnvironmentObject var viewModel: ViewModel

    // MARK: - View Model
    class ViewModel: ObservableObject {
        @Published var profileView: ProfileView?
        // 补充需要的@Published属性,确保属性变化能触发View更新
        @Published var topThreePublicUsers: [ExternalUser] = []
        @Published var publicLeaderboard: PublicLeaderboardView?
    }
      
    // MARK: - Body
    var body: some View {
        viewModel.profileView
    }
}

额外提示

  • 所有需要触发View更新的属性,必须在ViewModel中声明为@Published
  • 永远不要直接访问View的@EnvironmentObject或@StateObject属性,这类实例由SwiftUI生命周期管理,外部操作通过持有ViewModel实例完成即可

内容的提问来源于stack exchange,提问作者WikipediaBrown

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:16:19