SwiftUI嵌套@escaping闭包致@StateObject内存泄漏问题求助
SwiftUI嵌套@escaping闭包内存泄漏解决方案
问题核心
多层嵌套的@escaping闭包中,即便外层用了[weak viewModel],内层闭包如果隐式捕获外层的viewModel引用,加上IdentifiableAction被视图的@State持有,会形成循环引用链——视图持有@StateObject viewModel,viewModel被闭包捕获,闭包被IdentifiableAction包裹后存在@State中,最终导致内存泄漏。
关键解决思路
所有嵌套层级的闭包都必须显式添加弱引用捕获列表,并且用可选绑定确保引用有效后再执行逻辑,避免隐式强引用在嵌套链中传递。
修改后的代码示例
假设你的原实现代码如下:
struct IdentifiableAction: Identifiable, Hashable { let id = UUID() let action: () -> Void static func == (lhs: IdentifiableAction, rhs: IdentifiableAction) -> Bool { lhs.id == rhs.id } func hash(into hasher: inout Hasher) { hasher.combine(id) } } struct CheckModifier: ViewModifier { @Binding var pendingAction: IdentifiableAction? func body(content: Content) -> some View { content .onChange(of: pendingAction) { action in action?.action() } } } extension View { func check(action: Binding<IdentifiableAction?>) -> some View { self.modifier(CheckModifier(pendingAction: action)) } } class DetailViewModel: ObservableObject { func finalAction() { print("执行最终操作") } } struct DetailView: View { @StateObject private var viewModel = DetailViewModel() @State private var pendingAction: IdentifiableAction? var body: some View { Button("触发多层检查") { pendingAction = IdentifiableAction { [weak viewModel] in print("执行检查1") // 原内层闭包未显式捕获weak viewModel,导致泄漏 self.pendingAction = IdentifiableAction { print("执行检查2") self.pendingAction = IdentifiableAction { print("执行检查3") viewModel?.finalAction() } } } } .check(action: $pendingAction) } }
修改闭包捕获逻辑后的关键代码:
Button("触发多层检查") { pendingAction = IdentifiableAction { [weak viewModel] in print("执行检查1") guard let viewModel = viewModel else { return } // 内层闭包显式添加weak捕获 self.pendingAction = IdentifiableAction { [weak viewModel] in print("执行检查2") guard let viewModel = viewModel else { return } // 最内层同样显式捕获 self.pendingAction = IdentifiableAction { [weak viewModel] in print("执行检查3") viewModel.finalAction() } } } }
额外优化建议
- 如果需要访问视图的
pendingAction,建议同时捕获weak self,避免意外持有视图引用:
pendingAction = IdentifiableAction { [weak self, weak viewModel] in guard let self = self, let viewModel = viewModel else { return } print("执行检查1") self.pendingAction = IdentifiableAction { [weak self, weak viewModel] in guard let self = self, let viewModel = viewModel else { return } print("执行检查2") self.pendingAction = IdentifiableAction { [weak viewModel] in guard let viewModel = viewModel else { return } print("执行检查3") viewModel.finalAction() } } }
- 若能确保viewModel生命周期长于闭包执行周期,可尝试用
[unowned viewModel]替代weak,但需注意避免野指针访问风险。
内容的提问来源于stack exchange,提问作者Michał Ziobro
相关产品推荐
相关产品推荐

