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本身管理的正式实例,最终导致两次初始化。
修正方案
- 修改
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严格遵循视图生命周期,仅创建一次实例。
- 检查项目其他位置(如预览代码、导航跳转逻辑),确保没有重复创建
HomeViewModel的代码。
额外说明
@StateObject的设计初衷是绑定视图生命周期,确保对象在视图存在期间仅初始化一次。直接在属性定义处赋值的写法,会让SwiftUI在某些场景下(比如视图预览、状态更新的临时检查)触发额外的初始化操作。
内容的提问来源于stack exchange,提问作者Cook Kim
相关产品推荐
相关产品推荐

