SwiftUI视图结构体中memory leak问题排查求助
SwiftUI ObservableObject二维数组绑定引发内存泄漏的原因与修复方案
泄漏原因
问题出在ObservableObject嵌套集合的Binding强引用+闭包捕获的组合:
- 当你通过
$viewModel.mapData[0][0]创建Binding时,这个Binding会强引用EditFuelLevelViewModel实例——因为它需要监听数组元素的变更并同步视图,底层实现依赖对ViewModel的持有。 - TextField的
onEditingChanged闭包捕获了这个Binding,而TextField内部会保留该闭包的引用;再加上ContentView中的Timer持续触发重绘,旧的TableElement实例及其闭包无法被释放,最终导致ViewModel被永久持有,引发内存泄漏。
你提到的几种场景为什么不会泄漏:
- 注释回调:切断了闭包对Binding的捕获,引用链断裂。
- 移除绑定:没有了持有ViewModel的Binding,自然无泄漏。
- mapData改为@State:SwiftUI对@State的Binding采用内部优化管理,不会持有外部对象的强引用,因此无泄漏。
修复方案
避免直接绑定二维数组元素,改为传递ViewModel引用和索引,在闭包中用弱引用捕获ViewModel,打破强引用链:
修改后的TableElement代码
private struct TableElement: View { @ObservedObject var viewModel: EditFuelLevelViewModel let row: Int let col: Int @State private var text: String init(viewModel: EditFuelLevelViewModel, row: Int, col: Int) { self.viewModel = viewModel self.row = row self.col = col self.text = String(viewModel.mapData[row][col]) } var body: some View { TextField( "Enter Value", text: $text, onEditingChanged: { [weak viewModel] editing in guard let viewModel = viewModel else { return } if !editing { viewModel.mapData[row][col] = Float(text) ?? 0 } } ) } }
ContentView中调用方式
TableElement(viewModel: viewModel, row: 0, col: 0)
如果你的场景允许,也可以把二维数组的每个元素包装成独立的ObservableObject,这样单个元素的Binding不会持有整个ViewModel的强引用,但这种方式改动较大,适合更复杂的业务场景。
内容的提问来源于stack exchange,提问作者soltesza
相关产品推荐
相关产品推荐

