swift - 快速理解函数内的保留循环,Matt Neuburg 书中的一个例子
问题描述
考虑以下代码:
class myDropBounceAndRollBehavior: UIDynamicBehavior {
let v = UIView()
init(view v: UIView) {
self.v = v
super.init()
}
override func willMove(to anim: UIDynamicAnimator?) {
guard let anim = anim else {return}
let sup = self.v.superview!
let grav = UIGravityBehavior()
grav.action = { [unowned self] in
let items = anim.items(in: sup.bounds) as! [UIView]
if items.index(of: self.v) == nil {
anim.removeBehavior(self)
self.v.removeFromSuperview()
}
}
self.addChildBehavior(grav)
grav.addItem(self.v)
}
}
在这里,我们有一个类,该类的函数willMove(anim:)
具有引用自身的闭包,从而创建了一个保留循环。为了解决这个问题,马特self
开始unowned self
打破这个循环。
他的下一段是这样说的:
这里有一个潜在的(并且相当复杂的)保留循环:
self.addChildBehavior(grav)
导致对 的持久引用grav
,grav
具有对的持久引用grav.action
和分配给的匿名函数grav.action
引用self
。为了打破循环,我在匿名函数的捕获列表中声明了对self
as的引用unowned
根据书中的摘录,我为以下情况绘制了参考图,
因此,当函数willMove(anim:)
被触发时,将创建self.addChildBehavior(grav)
引用的函数调用,创建对引用实例的强引用。但是由于函数存在于主线程上,所以函数必须在释放堆内存之前完成,因此不再具有对 的强引用,并且可以完成并从堆中释放内存。结果将如下所示:grav
grav
willMove(anim:)
self.addChildBehavior(grav)
willMove(anim:)
self.addChildBehavior(grav)
grav
willMove(anim:)
此时,一旦willMove(anim:)
执行完成,剩下的唯一引用就是unowned self
对实例的引用和一些引用(例如let behavior = MyDropBounceAndRollBehaviour()
),然后一旦匿名函数执行完毕,它就只会behaviour
引用<MyDropAndBounceBehavior>
我有正确的理解吗?
解决方案
我将尝试用其他方式解释所有权周期:
self.behaviors -> grav -> action -> self
^ created by addChildBehavior(grav)
^ created by grav.action = {
^ created by capturing
self
拥有重力行为。重力行为拥有动作,动作捕捉(拥有)self
。
要打破所有权周期,您必须断开其中一个连接。一种解决方案是使用[weak self]
or来中断捕获[unowned self]
。
你的推理是错误的。当函数调用(例如willMove
)完成时,不会释放任何堆内存。仅当该内存不再拥有所有者时,才会释放引用计数内存管理中的堆内存。由于存在所有权周期,内存不能被释放。线程在这方面实际上没有任何作用。如果在同一个线程上调用所有内容(实际上可能发生),也会发生同样的情况。
我认为你的主要错误是self.addChildBehavior(grav)
保留的想法grav
。这不是真的。它永久添加grav
到所持有的行为列表中self
,这意味着创建一个强大的所有权self -> grav
。
推荐阅读
- javascript - 拒绝加载字体 '
' 因为它违反了以下内容安全策略指令 default-src ,所以使用 default-src 作为后备 - php - Laravel - 从关系中提取字段
- r - 在 R 和 Shiny 中使用 Keras 构建变分自动编码器
- java - 循环嵌套列表 RxJava2
- sql-server - 如何通过ssis包加载N条记录?
- java - ObjectOutputStream 重复输出
- scala - 我如何使用函数式编程思想重构它
- html - HTML/CSS:将鼠标悬停在部分显示的元素上时出现自动 scoll 问题
- rest - 用于自定义响应数据的 RESTful API 端点
- php - 即使名称正确,变量也无法从选择选项中获取值