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

模态视图关闭时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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 01:28:38