SwiftUI GeometryReader导致内存泄漏

时间:2020-01-22 09:41:23

标签: swiftui

考虑以下代码:

import SwiftUI

class ViewModel: ObservableObject {
}

struct TestView: View {
    @ObservedObject var vm = ViewModel()

    var body: some View {
//        self.sample
        GeometryReader { _ in
            self.sample
        }
    }

    var sample: some View {
        Text("Hello, World!")
    }
}

struct Tabs : View {
    @State var selection: Int = 0

    var body: some View {
        TabView(selection: $selection) {
            TestView().tabItem {
                Text("First Tab")
            }
            .tag(0)

            Text(String(selection))
            .tabItem {
                Text("Second Tab")
            }
            .tag(1)
        }
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
    }
}

有两个选项卡,选择是在主体中引用的,因此更改选择时将调用主体。 TestView正在使用GeometryReader。 当我从“第一个选项卡”切换到“第二个选项卡”时,将再次创建ViewModel,并且从未取消引用。这是意外的。 如果切换100次,我将从SwiftUI内部引用100个ViewModel。

尽管如果我删除GeometryReader,它会按预期工作。

有人经历过吗?有什么解决方法吗? 我只是希望将此ViewModel生存期绑定到TestView生存期。

更新:

XCode 11.3.1 iOS 13.3

1 个答案:

答案 0 :(得分:3)

好吧,让我们在ViewModel中进行以下更改

class ViewModel: ObservableObject {
    init() {
        print(">> inited") // you can put breakpoint here in Debug Preview
    }
}

所以现在看到了,因为View是值类型

struct TestView: View {
    @ObservedObject var vm = ViewModel() // << new instance on each creation
    ...

它起源于

var body: some View {
    TabView(selection: $selection) {
        TestView().tabItem { // << created on each tab switch
        ...

因此,解决方案是从ViewModel创建TestView并通过.environmentObject或通过构造函数参数注入外部实例。

顺便说一句,它不依赖于GeometryReader。经过Xcode 11.2.1 / iOS 13.2的测试