如何避免@State变量初始化时SwiftUI初始视图被多次初始化
问题根源
SwiftUI的视图是值类型,系统会根据状态变化、布局计算等场景多次创建视图结构体的副本,所以你看到init方法打印3次是正常现象,本身不会带来性能问题。
你遇到的CoreDataViewModel多次初始化、fetchItems()执行3次的核心问题是:你用@ObservedObject修饰并直接在视图内部初始化了ViewModel。@ObservedObject本身不负责持有对象实例,仅作为观察者存在,每次视图结构体重建时,赋值表达式CoreDataViewModel()都会执行,生成新的ViewModel实例,触发多次init和fetch操作。
解决方法
按你的使用场景二选一即可:
- 场景1:这个CoreDataViewModel仅在GroceryList视图内部使用
直接把@ObservedObject改为@StateObject即可。@StateObject是SwiftUI专门用来在视图内部持有可观察对象的属性包装器,对象实例只会在第一次创建视图时初始化一次,后续视图结构体重建时会复用已有的实例,不会重复生成。 - 场景2:这个CoreDataViewModel需要在多个视图间共享
不要在GroceryList内部初始化ViewModel,改在父视图、App入口结构体中用@StateObject初始化,再通过environmentObject注入到视图树中,GroceryList内部用@EnvironmentObject接收即可,全局只会有一个实例。
额外优化:可以把ViewModel init中的fetchItems()调用移到视图的.onAppear/.task修饰符中,同时在ViewModel内部加是否已拉取过数据的标记,避免意外重复拉取。
代码示例
单视图使用ViewModel写法
struct GroceryList: View { // 改为@StateObject持有,仅初始化一次 @StateObject var coreDataViewModel: CoreDataViewModel = CoreDataViewModel() @StateObject var userPreferences: UserPreferences = UserPreferences() @State private var selectedItemsInList: [GroceryItem] = [] @State private var selection = Set<UUID>() @State private var activeTab: Int = 0 init() { print("Grocery List View 结构体初始化,多次打印属于正常现象") } var body: some View { // 你的视图布局代码 List(coreDataViewModel.items) { item in // 列表项代码 } } }
多视图共享ViewModel写法
先在App入口初始化并注入:
@main struct YourGroceryApp: App { // 全局持有ViewModel实例 @StateObject private var coreDataViewModel = CoreDataViewModel() var body: some Scene { WindowGroup { GroceryList() // 注入到视图树 .environmentObject(coreDataViewModel) } } }
GroceryList内接收注入的实例:
struct GroceryList: View { // 接收环境中的ViewModel实例,不会重复初始化 @EnvironmentObject var coreDataViewModel: CoreDataViewModel @StateObject var userPreferences: UserPreferences = UserPreferences() @State private var selectedItemsInList: [GroceryItem] = [] @State private var selection = Set<UUID>() @State private var activeTab: Int = 0 }
内容的提问来源于stack exchange,提问作者udGlobal
相关产品推荐
相关产品推荐

