从 Form/NavigationView 中的闭包引用属性并交换视图时,SwiftUI 内存泄漏 [英] SwiftUI memory leak when referencing property from closure inside Form/NavigationView and swapping views
问题描述
我有这样的事情:
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
仍然被分配,因为 self.viewModel.logOut()
在 Button 的动作闭包中被调用并且 Button 持有对 SomeViewModel
.
When the button is pressed, SomeView
is closed and a different view is presented. 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
.
有办法解决这个问题吗?
Is there some way around this?
实际上,当没有将按钮包裹在 NavigationView
中时,没有泄漏.我一包住按钮,就会出现泄漏.包装在 VStack
中工作正常.但是包装在 Form
中再次产生泄漏.这里似乎是同样的问题:SwiftUI - 可能的内存泄漏
Actually, when not not wrapping the button in NavigationView
, there is no leak. As soon as I wrap the button, the leak appears. Wrapping in VStack
is working out fine. But wrapping in Form
produces the leak again. Seems like the same problem here: SwiftUI - Possible Memory Leak
推荐答案
我找到了一个解决方案:在您的操作中创建一个弱 viewModel
.苹果似乎改变了闭包的行为.这意味着 NavigationView
正在存储对 viewModel 的强引用.经过几天的调试,它终于对我有用了.
I found a solution: Make a weak viewModel
in your action. It seems that Apple changed the behavior of closures. This means that the NavigationView
is storing a strong reference to 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)
}
}
在最新的 Xcode 11.5 和 iOS 13.5 上测试.现在,在关闭视图后,viewModel
被正确释放.
Tested on the latest Xcode 11.5, with iOS 13.5. Now, after dismissing the view, the viewModel
is correctly deallocated.
这篇关于从 Form/NavigationView 中的闭包引用属性并交换视图时,SwiftUI 内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!