以下是我的自定义视图:
class CustomVIew: UIView {
deinit {
print("custom view deinit")
}
var onTapViewHandler: (()->Void)?
}
和视图控制器:
class ViewControllerB: UIViewController {
var customView: CustomVIew!
deinit {
print("B deinit")
}
override func viewDidLoad() {
super.viewDidLoad()
let customView = CustomVIew()
customView.onTapViewHandler = { [unowned self] in
self.didTapBlue()
}
customView.frame = CGRect(x: 50, y: 250, width: 200, height: 100)
customView.backgroundColor = UIColor.blueColor()
view.addSubview(customView)
self.customView = customView
}
func didTapBlue() {
}
}
当控制器从导航堆栈中弹出时,一切都很好:
B deinit
custom view deinit
但是当我替换这段代码时:
customView.onTapViewHandler = { [unowned self] in
self.didTapBlue()
}
与此:
customView.onTapViewHandler = didTapBlue
那么,控制台上什么也不打印。2 CustomView和ViewController没有发布,为什么?
为什么customView.onTapViewHandler = didTapBlue
捕获对self
的引用?
2条答案
按热度按时间eeq64g8w1#
Swift函数是闭包的一种,所以像闭包一样,函数也可以捕获引用。
当
customView.onTapViewHandler = didTapBlue
执行时,对self
的引用,即在这种情况下的ViewControllerB
引用将由函数调用捕获。同时,
ViewControllerB
的视图保持对CustomVIew
的强引用,因此它进行保留循环。关于使用
unowned
,Apple文档中指出:弱引用和无主引用使引用循环中的一个示例能够引用另一个示例,而无需保持对它的强控制。然后,示例可以相互引用,而无需创建强引用循环。
这意味着没有循环引用和保留循环。
vs3odd8k2#
如果将
[unowned self]
捕获列表添加到闭包中,则视图将保存对self
的弱引用,而self
将保存对该视图的强引用。由于没有任何东西对
self
有强引用,所以当视图控制器弹出时,self
可以被取消初始化。在self
被取消初始化后,没有任何东西对视图有强引用,所以 it 也被取消初始化。如果删除捕获列表,则
self
将保留对视图的强引用,而视图将保留对self
的强引用。这意味着要取消初始化self
,必须先取消初始化视图(这将破坏强引用)。但是为了使视图被取消初始化,必须先取消视图控制器的初始化,以中断对视图的强引用。但是,除非取消视图控制器的初始化,否则无法中断对视图的强引用。您可以'除非取消初始化视图,否则不要中断对视图控制器的强引用。看到了吗?我们在这里陷入了一个无限循环!所以视图和视图控制器都不会被取消初始化!