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
相关产品推荐
相关产品推荐

