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

SwiftUI中@StateObject与@EnvironmentObject共存时ViewModel初始化两次问题

SwiftUI中HomeViewModel重复初始化问题排查

我正在学习SwiftUI,采用MVVM模式并拆分视图以提升代码可读性,但发现HomeViewModel被初始化了两次,日志输出两次“HomeViewModel init !”。怀疑自身对配置存在理解误区,希望得到相关反馈与问题排查帮助。

相关代码

HomeView.swift

struct HomeView: View {
    
    @EnvironmentObject private var coordinator: Coordinator
    @StateObject var homeViewModel = HomeViewModel()
    
    init() {
        print("HomeView init!")
    }
    
    var body: some View {
        VStack {
            HomeButtons()
            
            TodaysCommit()

            CharacterView()

            CharacterInfo()
        }
        .environmentObject(homeViewModel)
        .onReceive(homeViewModel.$outputEvent) { event in
            if let event = event {
                receiveViewModelEvent(event)
            }
        }
    }
 
}

HomeButtons.swift

struct HomeButtons: View {
    @State private var showParticipating = false
    @State private var showingSheet = false
    @EnvironmentObject private var homeViewModel: HomeViewModel

    
    var body: some View {
        
        HStack {
            Button {
                homeViewModel.requestUserInfo()
            } label: {
                Image("refresh")
            }
            
            Spacer()
            Button {
                showParticipating.toggle()
            } label: {
                Image("collection")
            }
        }
        .sheet(isPresented: $showParticipating) {
            CollectionListView()
        }
        .padding(EdgeInsets(top: 0, leading: 30, bottom: 0, trailing: 30))
    }
    
    init() {
        UITabBar.appearance().backgroundColor = UIColor.white
        navigationBarHidden(false)
    }
}

日志输出

HomeView init!
HomeViewModel init !
HomeViewModel init !

问题原因与解决方法

核心原因

在HomeView中直接通过@StateObject var homeViewModel = HomeViewModel()的方式初始化对象,SwiftUI在视图渲染的临时校验或预览阶段,可能会额外创建一个HomeViewModel实例,再加上@StateObject本身管理的正式实例,最终导致两次初始化。

修正方案

  1. 修改HomeView中@StateObject的初始化方式,在init方法内通过StateObject(wrappedValue:)来初始化:
struct HomeView: View {
    @EnvironmentObject private var coordinator: Coordinator
    @StateObject var homeViewModel: HomeViewModel

    init() {
        print("HomeView init!")
        // 在这里初始化@StateObject
        _homeViewModel = StateObject(wrappedValue: HomeViewModel())
    }

    // 剩余代码保持不变
}

这种写法能确保@StateObject严格遵循视图生命周期,仅创建一次实例。

  1. 检查项目其他位置(如预览代码、导航跳转逻辑),确保没有重复创建HomeViewModel的代码。

额外说明

@StateObject的设计初衷是绑定视图生命周期,确保对象在视图存在期间仅初始化一次。直接在属性定义处赋值的写法,会让SwiftUI在某些场景下(比如视图预览、状态更新的临时检查)触发额外的初始化操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:00:01