简体   繁体   English

从 Form/NavigationView 中的闭包引用属性并交换视图时,SwiftUI 内存泄漏

[英]SwiftUI memory leak when referencing property from closure inside Form/NavigationView and swapping views

I have something like this:我有这样的事情:

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
  }
}

When the button is pressed, SomeView is closed and a different view is presented.按下按钮时, SomeView关闭并呈现不同的视图。 But if I check the memory graph, SomeViewModel is still allocated because self.viewModel.logOut() is called in the Button's action closure and Button is holding the reference to SomeViewModel .但是如果我检查内存图, SomeViewModel仍然被分配,因为在 Button 的动作闭包中调用了 self.viewModel.logOut self.viewModel.logOut()并且 Button 持有对SomeViewModel的引用。

Is there some way around this?有什么办法解决这个问题吗?

EDIT: Actually, when not not wrapping the button in NavigationView , there is no leak.编辑:实际上,当不在NavigationView中包装按钮时,没有泄漏。 As soon as I wrap the button, the leak appears.我一包裹按钮,就会出现泄漏。 Wrapping in VStack is working out fine.VStack中包装效果很好。 But wrapping in Form produces the leak again.但是用Form包装会再次产生泄漏。 Seems like the same problem here: SwiftUI - Possible Memory Leak在这里似乎是同样的问题: SwiftUI - Possible Memory Leak

I found a solution: Make a weak viewModel in your action.我找到了一个解决方案:在您的操作中创建一个弱viewModel It seems that Apple changed the behavior of closures. Apple 似乎改变了闭包的行为。 This means that the NavigationView is storing a strong reference to viewModel.这意味着NavigationView正在存储对 viewModel 的强引用。 After a couple days of debugging, it finally worked for me.经过几天的调试,它终于对我有用了。

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

In your problem, this will be solved like this:在您的问题中,这将像这样解决:

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

Tested on the latest Xcode 11.5, with iOS 13.5.在最新的 Xcode 11.5 和 iOS 13.5 上进行了测试。 Now, after dismissing the view, the viewModel is correctly deallocated.现在,在关闭视图后, viewModel被正确释放。

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

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