请考虑以下代码:
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:)的类,它具有引用自身的闭包,从而创建了一个保留循环。为了解决这个问题,Matt将self设置为unowned self以打破循环。
他的下一段说:
这里有一个潜在的(而且非常详细的)保留循环:
self.addChildBehavior(grav)导致对grav的持久引用,grav对grav.action的持久引用,分配给grav.action的匿名函数表示self。为了打破循环,我在匿名函数的捕获列表中将对self的引用声明为unowned
根据这本书的摘录,我为下面的情况绘制了参考图,

因此,当函数willMove(anim:)被触发时,将创建引用grav的函数调用grav,从而创建对grav引用实例的强引用。但是由于函数willMove(anim:)位于主线程上,函数self.addChildBehavior(grav) 必须在为willMove(anim:)释放堆内存之前完成,因此self.addChildBehavior(grav)不再对grav有很强的引用,willMove(anim:)可以完成并从堆中释放内存。结果如下:

此时,一旦willMove(anim:)完成了执行,剩下的唯一引用就是引用实例和一些引用的unowned self (例如let behavior = MyDropBounceAndRollBehaviour()),然后一旦匿名函数完成执行,那么它只会是引用<MyDropAndBounceBehavior>的behaviour。
我有正确的理解吗?
发布于 2019-02-14 19:46:20
我会尝试解释拥有权的循环,换言之:
self.behaviors -> grav -> action -> self
^ created by addChildBehavior(grav)
^ created by grav.action = {
^ created by capturingself拥有重力行为。重力行为拥有动作,动作捕获(拥有) self。
要打破所有权循环,您必须中断其中一个连接。一种解决方案是使用[weak self]或[unowned self]中断捕获。
你的推理是错误的。当函数调用(例如willMove)完成时,没有释放堆内存。引用计数内存管理中的堆内存只有在没有更多的内存所有者时才会释放。由于存在所有权周期,因此不能释放内存。线程在这方面并没有任何作用。如果在同一个线程上调用了所有东西(这实际上是可以发生的),那么同样的情况就会发生。
我认为您的主要错误是认为self.addChildBehavior(grav)保留了grav。那是胡说。它将grav永久添加到self保持的行为列表中,这意味着创建一个强大的所有权self -> grav。
发布于 2019-02-14 19:14:50
也许这会有帮助:
Self拥有grav (添加为子行为)。但是grav有一个拥有self (动作)的块。所以现在有了拥有self的self,这是一个保留周期。您可以在这里使用unowned self,因为如果self被解除分配,grav的块也会使用。当self拥有引用self的对象时,通常使用unowned self;否则,使用weak self。
https://stackoverflow.com/questions/54697060
复制相似问题