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

时间:2019-12-12 11:40:50

标签: ios memory-leaks swiftui

我有这样的东西:

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

1 个答案:

答案 0 :(得分:4)

我找到了解决方法:在您的操作中使弱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被正确释放。