首页 > 解决方案 > 带有表单和列表的 SwiftUI 内存泄漏

问题描述

我正在开发简单的待办事项应用程序SwiftUI。在我的测试中,我注意到我的视图模型从不调用 deinit 并导致内存使用量线性增加。

我使用以下代码重现了相同的行为:

struct ContentView: View {
    @State private var isPresented = false

    var body: some View {
        Button("open") {
            self.isPresented = true
        }
        .sheet(isPresented: $isPresented) {
            SheetView()
        }
    }
}

struct SheetView: View {
    @ObservedObject var model: ViewModel

    init() {
        model = ViewModel()
    }

    var body: some View {
        Form {
            Toggle("Toggle Me", isOn: $model.isOn)
        }
    }
}

class ViewModel: ObservableObject {
    @Published var isOn = false

    deinit {
        print("ViewModel deinit ")
    }
}

关闭工作表时,模型对象永远不会取消。如果我用 VStack 或 ScrollView 替换表单,则模型被取消。有针对这个的解决方法吗?

标签: iosmemory-leaksswiftui

解决方案


你理解deinit()错了。当您解雇 aView时,它并不一定意味着它会deinit()像您想的那样调用。如果你的ViewModel被摧毁,它会deinit()如你所愿地调用。

为了演示这一点,这里Person有一个具有 name 属性的类、一个简单的初始化程序和一个printGreeting()打印消息的方法:

class Person {
    var name = "John Doe"

    init() {
        print("\(name) is alive!")
    }

    func printGreeting() {
        print("Hello, I'm \(name)")
    }
}

我们将在Person循环中创建该类的一些实例,因为每次循环循环都会创建一个新人,然后将其销毁:

for _ in 1...3 {
    let person = Person()
    person.printGreeting()
}

现在是反初始化器。这将在Person实例被销毁时调用:

deinit {
    print("\(name) is no more!")
}

资料来源:https ://www.hackingwithswift.com/sixty/8/6/deinitializers


推荐阅读