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

SwiftUI视图结构体中memory leak问题排查求助

SwiftUI ObservableObject二维数组绑定引发内存泄漏的原因与修复方案

泄漏原因

问题出在ObservableObject嵌套集合的Binding强引用+闭包捕获的组合:

  1. 当你通过$viewModel.mapData[0][0]创建Binding时,这个Binding会强引用EditFuelLevelViewModel实例——因为它需要监听数组元素的变更并同步视图,底层实现依赖对ViewModel的持有。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 18:20:56