模态视图关闭时ViewModel Observable Object未被销毁的原因咨询
问题原因及解决方案
为什么ViewModel不会被销毁?
你遇到的问题核心在于fullScreenCover的content闭包特性,以及@ObservedObject的引用机制:
- 当你在
fullScreenCover的闭包里创建ViewModel并传入PresentedView时,SwiftUI内部渲染机制可能会额外持有这个ViewModel的引用,即便模态视图关闭,这个隐性引用也不会立即释放。 @ObservedObject本身会强引用传入的ViewModel,理论上它的生命周期和视图绑定,但这里因为闭包的惰性求值和SwiftUI的缓存逻辑,导致视图销毁后,ViewModel仍被挂住,无法触发deinit。
解决办法
有两种常用修复方式,可根据需求选择:
1. 用@StateObject在PresentedView内部管理ViewModel
把ViewModel的创建移到PresentedView里,用@StateObject持有,SwiftUI会完全接管其生命周期——视图销毁时,ViewModel会自动被释放:
struct PresentedView: View { @Environment(\.dismiss) var dismiss @StateObject private var vm = ViewModel() var body: some View { Text("Presented View").onTapGesture { dismiss() } } } // ContentView中的fullScreenCover简化为: .fullScreenCover(isPresented: $isPresented) { PresentedView() }
2. 用fullScreenCover(item:)绑定ViewModel
如果需要在外部创建ViewModel(比如传递初始化参数),可以用item绑定的版本,通过控制可选对象的nil状态触发销毁:
struct ContentView: View { @State var presentedVM: ViewModel? var body: some View { Button("Present!") { presentedVM = ViewModel() } .fullScreenCover(item: $presentedVM) { vm in PresentedView(vm: vm) } } } struct PresentedView: View { @Environment(\.dismiss) var dismiss @ObservedObject var vm: ViewModel var body: some View { Text("Presented View").onTapGesture { dismiss() } } } // 给ViewModel添加Identifiable协议,满足item绑定的类型要求 extension ViewModel: Identifiable { var id: UUID { UUID() } }
调用dismiss()时,presentedVM会自动被置为nil,ViewModel失去所有强引用,就能触发deinit了。
内容的提问来源于stack exchange,提问作者Nader
相关产品推荐
相关产品推荐

