SwiftUI(Mac)@Observable数组引发内存泄漏及App生命周期重复触发问题
SwiftUI @Observable 数组访问引发的重复初始化与生命周期异常问题
问题现象
使用带有数组属性的@Observable视图模型时,若在init方法中访问数组(例如判断isEmpty),修改数组会触发WindowGroup的body重新计算,导致视图模型被二次初始化,出现以下异常:
- 首次运行打印
Init,点击Update按钮后再次打印Init - 内存中存在两个
ContentViewModel实例,deinit方法从未触发 - 移除
if items.isEmpty {}代码后问题完全消失,且该问题仅出现在@Observable中,ObservableObject+ObservedObject组合无此现象
复现代码
Root App
@main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }
ViewModel
@Observable class ContentViewModel { var items = [String]() init() { print("Init") if items.isEmpty {} // 触发问题的关键代码 } deinit { print("deinit") } func update() { items.append("New") } }
View
struct ContentView: View { @State var viewModel: ContentViewModel = .init() var body: some View { Button("Update", action: viewModel.update) } }
原因分析
这是@Observable宏的属性观察机制导致的:@Observable采用细粒度的属性访问追踪,在init方法中访问数组属性时,会提前将观察关联绑定到App场景的生命周期上下文。当数组被修改时,错误地触发了WindowGroup的视图刷新,进而导致@State包装的视图模型被重新初始化,旧实例因仍被观察关联引用而无法释放。
而ObservableObject基于@Published的发布订阅模型,仅在属性显式发布时触发视图更新,不会在init阶段建立错误的观察绑定,因此无此问题。
解决方案
方案1:延迟数组逻辑到视图初始化后执行
将原init中的数组访问逻辑移到视图的onAppear回调中执行,避免在@Observable的init中触发观察关联:
修改ViewModel:
@Observable class ContentViewModel { var items = [String]() init() { print("Init") } deinit { print("deinit") } func setup() { if items.isEmpty {} // 原init中的逻辑移到此处 } func update() { items.append("New") } }
修改ContentView:
struct ContentView: View { @State var viewModel: ContentViewModel = .init() var body: some View { Button("Update", action: viewModel.update) .onAppear(perform: viewModel.setup) } }
方案2:改用ObservableObject实现
如果业务允许,切换到ObservableObject+@Published的组合,规避@Observable的当前问题:
class ContentViewModel: ObservableObject { @Published var items = [String]() init() { print("Init") if items.isEmpty {} } deinit { print("deinit") } func update() { items.append("New") } }
视图中使用@StateObject:
struct ContentView: View { @StateObject var viewModel: ContentViewModel = .init() var body: some View { Button("Update", action: viewModel.update) } }
内容的提问来源于stack exchange,提问作者bauerMusic
相关产品推荐
相关产品推荐

