在据我所知,不应该泄漏的情况下,我正在经历与无主的自我泄漏。让我举个例子,这有点做作,所以请耐心等待,我已经尽力制作最简单的案例。
假设我有一个简单的视图控制器,它在 viewDidLoad 上执行一个闭包:
class ViewController2: UIViewController {
var onDidLoad: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
onDidLoad?()
}
}
和一个类,ViewHandler,它拥有这个视图控制器的一个实例,并使用一个无主引用将一个通知函数的调用注入到它的闭包中:
class ViewHandler {
private let viewController2 = ViewController2()
func getViewController() -> ViewController2 {
viewController2.onDidLoad = { [unowned self] in
self.notify()
}
return viewController2
}
func notify() {
print("My viewcontroller has loaded its view!")
}
}
然后,当它的视图控制器由另一个视图控制器呈现时,ViewHandler 在被取消时泄漏:
class ViewController: UIViewController {
private var viewHandler: ViewHandler?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
viewHandler = ViewHandler()
self.present(viewHandler!.getViewController(), animated: true, completion: nil)
viewHandler = nil // ViewHandler is leaking here.
}
}
我知道这个例子可能看起来有点做作,但据我所知不应该有泄漏。让我尝试分解它:
在呈现 ViewHandler.ViewController2 之前,所有权应如下所示:
ViewController -> ViewHandler -> ViewController2 -|
^ |
|_ _ _ _ unowned _ _ _ _ _ |
呈现 ViewHandler.ViewController2 后,所有权应如下所示:
_______________________________
| v
ViewController -> ViewHandler -> ViewController2 -|
^ |
|_ _ _ _ unowned _ _ _ _ _ |
取消 ViewHandler 后,所有权应如下所示:
_______________________________
| v
ViewController ViewHandler -> ViewController2 -|
^ |
|_ _ _ _ unowned _ _ _ _ _ |
没有任何东西拥有 ViewHandler,它应该被释放。然而,情况并非如此,ViewHandler 正在泄漏。
如果我将注入到 onDidLoad 的闭包的捕获列表中的引用更改为弱,则没有泄漏并且 ViewHandler 按预期释放:
func getViewController() -> ViewController2 {
viewController2.onDidLoad = { [weak self] in
self?.notify()
}
return viewController2
}
另外,我无法解释的事情是,如果我将引用保持为无主并使 ViewHandler 从 NSObject 继承,ViewHandler 将按预期释放并且没有泄漏:
class ViewHandler: NSObject {
private let viewController2 = ViewController2()
func getViewController() -> ViewController2 {
viewController2.onDidLoad = { [unowned self] in
self.notify()
}
return viewController2
}
....
}
任何人都可以解释发生了什么?