【问题标题】:SwiftUI memory leak when referencing property from closure inside Form/NavigationView and swapping views从 Form/NavigationView 内部的闭包中引用属性并交换视图时 SwiftUI 内存泄漏
【发布时间】:2020-04-05 19:08:52
【问题描述】:

我有这样的事情:

struct SomeView: View {
  @ObservedObject var viewModel: SomeViewModel

  var body: some View {
     NavigationView { // <- culprit
        Button(action: { self.viewModel.logOut() }) { Text("X").frame(width: 40, height: 40) }
     }
}

class SomeViewModel: ObservableObject {
  func logOut() {
  // changes global state, based on which the views are swapped, so `SomeView` is removed and replaced by a different one
  }
}

按下按钮时,SomeView 关闭并呈现不同的视图。但是如果我检查内存图,SomeViewModel 仍然被分配,因为在 Button 的操作闭包中调用了self.viewModel.logOut(),并且 Button 持有对SomeViewModel 的引用。

有办法解决这个问题吗?

编辑: 实际上,当不将按钮包裹在NavigationView 中时,没有泄漏。一旦我包裹按钮,就会出现泄漏。包裹VStack 效果很好。但是包裹在Form 中会再次产生泄漏。这里似乎是同样的问题:SwiftUI - Possible Memory Leak

【问题讨论】:

  • 您是否尝试过在闭包中调用 self.logOut() 之类的东西,它会在 self.viewModel.logOut() 内部调用。只是很有趣会有什么不同。
  • 是的,我确实尝试过这个和其他一些方法 - 没有任何效果。只是不在按钮周围使用 NavigationView/List/Form 不会造成泄漏......但这对我没有任何帮助。
  • 你能不能在 onDisappear{} 中调用`self.viewModel.logOut()` 并且按钮只是用于弹出或关闭SomeView
  • 当你说有泄漏时,这是一个随着每次交互而增长的持续泄漏吗?或者它是一次发生的事情?泄漏了多少字节?小的泄漏(16 字节是最常见的)在 UIKit 中是完全正常的。 UIKit 本身就有内存泄漏。
  • @Rob Napier 每次我来回走动时,都会创建新的 ViewModel 而旧的 ViewModel 保留在内存中。在我的真实代码中,每个模型也有自己的服务,并且该服务也保留在内存中。它不断产卵和产卵。所以这不是微不足道的。

标签: ios memory-leaks swiftui


【解决方案1】:

我找到了一个解决方案:在你的行动中做一个弱的viewModel。苹果似乎改变了闭包的行为。这意味着 NavigationView 正在存储对 viewModel 的强引用。经过几天的调试,它终于对我有用了。

Button(action: { 
    [weak viewModel] in viewModel?.dismissButtonPressed.send(())
}) {
    Image("crossmark")
        .padding()
        .foregroundColor(Color.white)
    }
}

在你的问题中,这将是这样解决的:

NavigationView { 
    [weak viewModel] in Button(action: { viewModel?.logOut() }) {
        Text("X").frame(width: 40, height: 40)
    }
}

在最新的 Xcode 11.5 和 iOS 13.5 上测试。现在,关闭视图后,viewModel 已正确释放。

【讨论】:

  • 自从我一直在努力解决这个问题以来,我已经转向了一个全局状态 + 修改该状态的操作,而不是使用本地视图模型。实际上,我什至也停止使用 NavigationView,因为它还有一些其他问题,转而支持自定义路由处理。但这看起来确实合法,所以我现在将其标记为正确答案。谢谢!
  • 太棒了!这对我的情况很有帮助,我有一个带有多个按钮和一个菜单的toolbar,它们都在访问EnvironmentObject。在我在捕获列表中应用unowned 后,我的内存泄漏得到了修复!谢谢!
猜你喜欢
  • 2020-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-12
  • 2020-01-23
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多