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

