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

SwiftUI中Task{ }的正确用法及内存泄漏问题确认

SwiftUI中Task{}的内存泄漏与循环引用验证

先看你提供的示例代码:

struct MyView: View {
    @ObservedObject var viewModel: ViewModel

    var body: some View {
        VStack {
            Text(viewModel.publishedString)
        }
        .onAppear(perform: {
            Task {
                viewModel.resetUI()
                await viewModel.doSomeAsyncStuff()
            }
        })
        .onDisappear {
            Task {
                await viewModel.doAnotherAsyncStuff()
                viewModel.resetUI()
            }
        }
    }
}

针对你提出的6个理解点,逐一验证如下:

  • 第1点:正确。Task闭包会捕获当前的MyView结构体实例(值类型),捕获时会自动创建一份副本存储在闭包环境中。
  • 第2点:正确。MyView结构体的副本同样持有ViewModel类的强引用——因为@ObservedObject本质就是对引用类型实例的强引用,副本只是复制了这个引用指针。
  • 第3点:正确。ViewModel是引用类型,它的引用只是指向已有实例的指针,不会额外分配新内存;而MyView是值类型,副本会分配独立的内存空间,当Task闭包执行完成后,这个副本会被系统自动销毁释放内存。
  • 第4点:正确。所有MyView的结构体实例(包括闭包里的副本)都指向同一个ViewModel实例,当ViewModel的@Published属性publishedString更新时,会触发SwiftUI的视图刷新机制,通知所有订阅该属性的活跃视图重新计算body。
  • 第5点:正确。Task闭包执行完毕后,其捕获的MyView副本不再被任何代码引用,会被ARC自动回收释放。
  • 第6点:基本正确(需补充前提)。如果初始MyView实例已经被释放,且没有其他地方持有ViewModel的强引用,那么Task闭包里的MyView副本会一直持有ViewModel的强引用直到Task完成;Task结束后,副本被释放,ViewModel的引用计数归零,也会被系统释放。但如果ViewModel还被其他对象(比如父视图、其他逻辑模块)强引用,那即使Task完成,ViewModel也不会被释放。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:46:30