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

iOS 15中使用@Published变量时如何销毁StateObject?

iOS 15 中 StateObject 绑定 .alert() 导致内存泄漏的解决方案

在 iOS 15 环境下,当使用 StateObject 的 @Published 属性绑定 .alert() 的 isPresented 参数时,会出现 ViewModel 无法触发 deinit 的内存泄漏问题——这是因为 View 持有了 @Published 属性的 Publisher 引用,导致整个 StateObject 无法被销毁。iOS 16 已修复此问题,以下是针对 iOS 15 的几种解决办法:

方法一:使用本地 @State 中转绑定

通过本地 @State 变量作为 .alert() 的绑定源,再同步 StateObject 中的属性,避免直接绑定 @Published 属性导致的引用持有:

struct ChildView: View {
    @StateObject private var vm = ChildViewModel()
    @State private var localShowingAlert = false // 本地中转变量
    
    var body: some View {
        Text("Hello, World!")
            .alert("Alert Title", isPresented: $localShowingAlert, actions: {
                Button("OK") { }
            }, message: {
                Text("Alert Message")
            })
            // 同步 ViewModel 的属性到本地变量
            .onReceive(vm.$showingAlert) { newValue in
                localShowingAlert = newValue
            }
            // 同步本地变量的变化回 ViewModel
            .onChange(of: localShowingAlert) { newValue in
                if !newValue {
                    vm.showingAlert = newValue
                }
            }
    }
}

方法二:自定义 Binding 避免持有 Publisher

创建自定义 Binding,直接访问 StateObject 的属性而不使用自动生成的 $ 绑定(该绑定会持有 Publisher):

struct ChildView: View {
    @StateObject private var vm = ChildViewModel()
    
    var body: some View {
        Text("Hello, World!")
            .alert("Alert Title", isPresented: Binding(
                get: { vm.showingAlert },
                set: { vm.showingAlert = $0 }
            ), actions: {
                Button("OK") { }
            }, message: {
                Text("Alert Message")
            })
    }
}

方法三:在 View 消失时重置属性并断开关联

利用 .onDisappear 回调,在 View 销毁前重置 @Published 属性,帮助打破引用循环:

struct ChildView: View {
    @StateObject private var vm = ChildViewModel()
    
    var body: some View {
        Text("Hello, World!")
            .alert("Alert Title", isPresented: $vm.showingAlert, actions: {
                Button("OK") { }
            }, message: {
                Text("Alert Message")
            })
            .onDisappear {
                vm.showingAlert = false
            }
    }
}

以上三种方法中,方法一和方法二更可靠,能彻底避免引用持有问题;方法三作为临时 workaround,适用于简单场景。

内容的提问来源于stack exchange,提问作者Stan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 12:35:07