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

SwiftUI中onSubmit导致视图实例无法释放的问题排查

SwiftUI onSubmit闭包访问@State/@Binding引发的内存泄漏问题

在SwiftUI中,若在onSubmit修饰符的闭包内直接访问视图自身的@State或@Binding属性,会导致视图实例无法被正常释放,始终有一个实例驻留在内存中。

验证结果

通过切换显示/隐藏带有onSubmit修饰符的Input视图,多次操作后的控制台输出如下:

[Input] constructed: (1)
[Input] constructed: (2)
[Input] deallocating: (1)
[Input] constructed: (2)
[Input] deallocating: (1)
[Input] constructed: (2)
[Input] deallocating: (1)

可见每次创建新实例后,仅释放一个旧实例,始终有一个实例存活,存在内存泄漏。

若注释掉onSubmit代码行,或者将其替换为onTapGesture,视图实例则能正常释放,控制台输出恢复正常:

[Input] constructed: (1)
[Input] deallocating: (0)
[Input] constructed: (1)
[Input] deallocating: (0)
[Input] constructed: (1)
[Input] deallocating: (0)
[Input] constructed: (1)
[Input] deallocating: (0)

完整代码示例

import SwiftUI

struct ContentView : View {
    
    @State private var state: Bool = false
    
    var body: some View {
        VStack {
            Button("push") { state.toggle() }
            if state { Input() } else { Color.red }
        }
    }
    
}

struct Input : View {
    
    @State private var text: String
    @State private var whatever: Bool
    private let tracing: InstanceTracer
    
    init() {
        self.text = "text"
        self.whatever = true
        self.tracing = InstanceTracer("Input")
    }
    
    var body: some View {
        TextField("placeholder", text: $text)
            .onSubmit { whatever.toggle() } // <- 此处导致实例无法释放
    }
    
}

final class InstanceTracer {
    
    private static var instances: [String : Int] = [ : ]
    
    private let name: String
    
    init(_ name: String) {
        self.name = name
        print("[\(name)] constructed: (\(increment(numberOf: name)))")
    }
    
    deinit { print("[\(name)] deallocating: (\(decrement(numberOf: name)))") }
    
    private func increment(numberOf name: String) -> Int {
        var number: Int = Self.instances[name] ?? 0
        number += 1
        Self.instances[name] = number
        return number
    }
    
    private func decrement(numberOf name: String) -> Int {
        var number: Int = Self.instances[name] ?? 0
        guard number > 0 else { return 0 }
        number -= 1
        Self.instances[name] = number
        return number
    }
    
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 20:13:14