【问题标题】:@StateObject never gets destroyed@StateObject 永远不会被破坏
【发布时间】:2021-10-25 14:54:57
【问题描述】:

我正在使用@StateObject 为我的视图创建视图模型。问题是 ViewModel 在关闭视图后仍在内存中,并且从未调用 deinit。如果我打开和关闭视图 10 次,调试内存图会显示 10 个 ViewModel。我创建了一个非常简单的示例来复制问题:

import SwiftUI

struct MySwiftUIView: View {
    @Environment(\.presentationMode) private var presentation
    @StateObject var viewModel = MyViewModel()

        var body: some View {
                Text("Hallo World.")
                    .navigationBarBackButtonHidden(true)
                    .navigationBarItems(leading: Button(
                        action: {
                            presentation.wrappedValue.dismiss()
                    },
                        label: { Text("back") }))
            }
    }

class MyViewModel: ObservableObject {
    init() {
        print(">> init")
    }

    deinit {
        print("[x] deinit")
    }
}

每次打开视图时都会打印“>> init”,但从不打印“[x] deinit”。

这就是我打开视图的方式:

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack{
                NavigationLink(destination: MySwiftUIView()){Text("NavigationLink")}
            }
        }.navigationViewStyle(StackNavigationViewStyle())
    }
}

有人知道为什么 ViewModel 永远不会被破坏吗?

我在 Xcode 中创建了一个演示项目,可以在这里找到:https://file.io/QQnHDvRNaGPP

【问题讨论】:

  • 我正在使用 XCode 13 beta 5,它对我来说可以正常工作。当按下后退按钮时,deinit 打印正确。
  • @runemonster 这个问题不是针对iOS 15的,所以请在当前稳定的iOS版本上测试。人们现在遇到问题,即使它在 iOS 15 中得到修复,他们也在寻找当前版本的解决方案,当它被 iOS 15 取代时,许多支持它的人仍然需要修复。
  • 所以我测试了 ViewModel 没有正确调用 deinit 的原因是 navigationBarItems 在关闭时没有正确删除对页面的所有引用。您的应用程序的目标版本是什么?如果它是 14 或更高,您可以更新到 ToolbarItem 这将使您的 deinit 被正确调用。
  • @runemonster:我的目标版本是iOS14。谢谢你的tipp,我会试试的。
  • 如果你因为某种原因必须使用navigationBarItems。这个堆栈答案应该会有所帮助。我试过了,它奏效了。 stackoverflow.com/a/61305155/6122879

标签: ios swift swiftui


【解决方案1】:

runemonster 在 cmets 中建议的解决方案有效。如果我使用 Toolbar 而不是 navigationBarItems,内存泄漏就会消失:

struct MySwiftUIView: View {
    @Environment(\.presentationMode) private var presentation
    @StateObject var viewModel = MyViewModel()

        var body: some View {
                Text("Hallo World.")
                .navigationBarBackButtonHidden(true)
                .toolbar {
                    ToolbarItem(placement: .navigationBarLeading) {
                            Button("Back") {
                                presentation.wrappedValue.dismiss()
                            }
                        }
                }
            }
    }

class MyViewModel: ObservableObject {
    init() {
        print(">> init")
    }

    deinit {
        print("[x] deinit")
    }
}

【讨论】:

  • 请在此提交雷达并分享。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-15
  • 1970-01-01
  • 1970-01-01
  • 2020-11-18
  • 2012-10-27
  • 2013-10-12
相关资源
最近更新 更多