简体   繁体   English

SwiftUI 在视图层次结构中保留循环

[英]SwiftUI retain cycle in view hierarchy

I'm having the following view hierarchy which has a retain cycle, that's the simplest I could make to reproduce the issue.我有以下具有保留周期的视图层次结构,这是我可以重现问题的最简单方法。 All viewmodels and properties has to stay as they are needed in the original solution:所有视图模型和属性都必须保留,因为它们在原始解决方案中是需要的:

import SwiftUI

struct MainView: View {
    @StateObject var viewModel = MainViewModel()

    var body: some View {
        NavigationView { [weak viewModel] in
            VStack {
                Button("StartCooking") {
                    viewModel?.show()
                }

                if viewModel?.isShowingContainerView == true {
                    ContainerView()
                }
                Button("StopCooking") {
                    viewModel?.hide()
                }
            }
        }
        .navigationViewStyle(.stack)
    }
}

final class MainViewModel: ObservableObject {
    @Published var isShowingContainerView = false

    func show() {
        isShowingContainerView = true
    }

    func hide() {
        isShowingContainerView = false
    }
}

struct ContainerView: View {
    @Namespace var namespace

    var body: some View {
        VStack {
            SubView(
                namespace: namespace
            )
        }
    }
}


struct SubView: View {
    @StateObject var viewModel = SubViewModel()
    var namespace: Namespace.ID

    var body: some View {
        Text("5 min")
            .matchedGeometryEffect(id: UUID().uuidString, in: namespace)
            .onTapGesture {
                foo()
            }
    }

    private func foo() {}
}


final class SubViewModel: ObservableObject {}

If I run the app, tap on StartCooking , than on StopCooking and check the memory graph, I still see an instance of SubViewModel , which means that there is a leak in this code.如果我运行应用程序,点击StartCooking ,然后点击StopCooking并检查 memory 图,我仍然看到SubViewModel的实例,这意味着此代码中存在泄漏。 If I remove:如果我删除:

  • NavigationView OR NavigationView
  • The VStack from ContainerView OR来自ContainerView的 VStack 或者
  • matchedGeometryEffect OR matchedGeometryEffect
  • tapGesture

The retain cycle is resolved.保留周期已解决。 Unfortunately I need all these.不幸的是我需要所有这些。 Can you see what the issue might be and how could it be solved?您能看出问题可能是什么以及如何解决吗?

Looks like a SwiftUI bug.看起来像一个 SwiftUI 错误。 A possible workaround (if sub-view is one or limited set) is to use view model factory to provided instances.一种可能的解决方法(如果子视图是一个或有限的集合)是使用视图 model 工厂来提供实例。

Here is an example for one view:这是一个视图的示例:

struct SubView: View {

    @StateObject var viewModel = SubViewModel.shared  // single instance !!

    // .. other code
}

final class SubViewModel: ObservableObject {
    static var shared = SubViewModel()         // << this !!
}

I could kind of workaround it by making every property optional in the SubViewModel and running a function when the SubView s disappear, which makes them nil .我可以通过在 SubViewModel 中使每个属性都是可选的并在SubViewModel消失时运行SubView来解决它,这使它们成为nil The SubViewModel still stays in the memory, but will not take up that much space. SubViewModel仍然停留在 memory,但不会占用那么多空间。

Interestingly I even tried to make the viewmodel optional, and make it nil when the view disappears, but it still stayed in the memory.有趣的是,我什至尝试将 viewmodel 设为可选,并在视图消失时将其设为 nil,但它仍然停留在 memory。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM