首页 > 解决方案 > 快速理解函数内的保留循环,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)导致对 的持久引用gravgrav具有对的持久引用grav.action和分配给的匿名函数grav.action引用self。为了打破循环,我在匿名函数的捕获列表中声明了对selfas的引用unowned

根据书中的摘录,我为以下情况绘制了参考图,

在此处输入图像描述

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

在此处输入图像描述

此时,一旦willMove(anim:)执行完成,剩下的唯一引用就是unowned self对实例的引用和一些引用(例如let behavior = MyDropBounceAndRollBehaviour()),然后一旦匿名函数执行完毕,它就只会behaviour引用<MyDropAndBounceBehavior>

我有正确的理解吗?

标签: swiftclosuresautomatic-ref-counting

解决方案


我将尝试用其他方式解释所有权周期:

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


推荐阅读