iOS 17 中的 SwiftUI View 泄漏

问题描述 投票:0回答:1

视图及其成员在演示后不会释放:

@main
struct ExampleApp: SwiftUI.App {
    @State var show = false

    var body: some Scene {
        WindowGroup {
            VStack {
                Button("Present") { show = true }
                Text("First")
                    .fullScreenCover(isPresented: $show) {
                        CheckSecond { show = false }
                    }
            }
        }
    }
}

struct CheckSecond: View {
    private let log = LogDeinit()
    var action: () -> Void
    
    var body: some View {
        Text("Second")
        Button("Back"){ action() }
    }
}

class LogDeinit {
    init(name: String) { print("init") }    
    deinit { print("deinit") }
}

来回显示“CheckSecond”会导致控制台中出现“init”,但不会出现“deinit”。内存映射显示“LogDeinit”对象由单个 SwiftUI 对象引用,无需任何额外连接。在 iOS 16 中可以正常工作 - 每次关闭时都会打印“deinit”。看来真的漏水了。

swiftui view memory-leaks ios17
1个回答
-1
投票

大多数人已经知道

@ObservedObject
是泄露,因为苹果在 WWDC 视频中这么说,例如这有一个严重的泄漏:

struct BadLeakView: View {
    @ObserverdObject var log = LogDeinit() // bad leak

然而,你的示例是一个更严重的泄漏,因为你不仅在 View 结构中初始化了一个对象(SwiftUI 保留了

View
结构的许多副本,以便可以区分它们),而且你甚至没有将其包装在任何属性包装器中,例如这是一次非常严重的泄漏:

struct VeryBadLeakView: View {
    let log = LogDeinit() // very bad leak!

您可以使用

@StateObject
修复此问题,但是您应该质疑是否需要一个对象,通常只有当您需要执行异步操作(例如组合管道)时才需要。由于我们现在有了 async/await,通常你甚至不再需要
@StateObject
,因为我们有
.task
,它就像一个状态对象,但作为一个更简单的视图修饰符。

© www.soinside.com 2019 - 2024. All rights reserved.