[英]Swift - Holding closure reference leaks
為什么持有對閉包的引用會導致 memory 泄漏,即使閉包不保留任何內容?
(這始於SwiftUI
問題,但我不確定它是否真的相關)
所以這里有一個簡單的 Manager ( ViewModel
),它包含一個閉包。
class Manager: ObservableObject {
private var handler: (() -> Void)?
deinit {
print("Manager deallocated")
}
func shouldDismiss(completion: @escaping () -> Void) {
handler = completion
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.handler?()
}
}
}
這是一個視圖,使用它:
struct LeakingView: View {
@ObservedObject var manager: Manager
let shouldDismiss: () -> Void
var body: some View {
Button("Dismiss") { [weak manager] in
manager?.shouldDismiss {
shouldDismiss()
}
}
}
}
這是一個激活流程的ViewController
:
class ViewController: UIViewController {
var popup: UIViewController?
@IBAction func openViewAction(_ sender: UIButton) {
let manager = Manager()
let suiView = LeakingView(manager: manager) { [weak self] in
self?.popup?.view.removeFromSuperview()
self?.popup?.dismiss(animated: true)
self?.popup = nil
}
popup = LKHostingView(rootView: suiView)
popup?.view.frame.size = CGSize(width: 300, height: 300)
view.addSubview(popup!.view)
}
}
運行時,只要 manager 持有閉包,它就會泄漏,並且Manager
不會被釋放。
保留周期在哪里?
為什么持有對閉包的引用會導致 memory 泄漏,即使閉包不保留任何內容?
因為閉包確實保留了一些東西。 它保留self
。
例如,當你說
manager?.shouldDismiss {
shouldDismiss()
}
第二個shouldDismiss
表示self.shouldDismiss
並保留self
。 因此,LeakingView 保留了 Manager,但 Manager 通過關閉,現在保留了 LeakingView。 保留周期
這就是為什么人們在此類關閉開始時會說[weak self] in
。
我建議您可能不想在這里使用[weak self]
模式。 您正在定義應該在視圖被關閉后 ½ 秒發生的事情。 因此,您可能希望保留該強參考,直到所需的操作完成。
一種方法是確保Manager
在調用處理程序后簡單地刪除其強引用:
class Manager: ObservableObject {
private var handler: (() -> Void)?
func shouldDismiss(completion: @escaping () -> Void) {
handler = completion
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.handler?()
self.handler = nil
}
}
}
或者,如果此完成處理程序的使用確實僅限於此方法,您可以將其簡化為:
class Manager: ObservableObject {
func shouldDismiss(completion: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
completion()
}
}
}
或者
func shouldDismiss(completion: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: completion)
}
所有這些方法都將確保Manager
不會保留任何超出必要時間的強引用。
現在,調用者可以選擇使用[weak self]
如果它願意(即,如果它不希望捕獲的引用甚至存活 ½ 秒),但如果你真的想要“做某事之后它是解雇”,它可能也不會使用weak
引用。 但無論哪種方式,它都應該取決於調用者,而不是經理。 經理應該確保它不會在不再需要的情況下繼續關閉。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.