理解保留在swift函数中的循环,Matt Neuburg的书中的一个例子

问题描述 投票:1回答:2

考虑以下代码:

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。为了打破这个循环,我在匿名函数的捕获列表中将self的引用声明为unowned

通过本书的摘录,我为下面的情况制定了参考图,

enter image description here

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

enter image description here

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

我有正确的理解吗?

swift closures automatic-ref-counting
2个回答
1
投票

我将尝试用其他话来解释所有权周期:

self.behaviors -> grav -> action -> self
               ^ created by addChildBehavior(grav)
                       ^ created by grav.action = {
                                  ^ created by capturing

self拥有引力行为。引力行为拥有动作,动作捕获(拥有)self

要打破所有权周期,您必须打破其中一个连接。一种解决方案是使用[weak self][unowned self]打破捕获。

你的推理是错误的。当函数调用(例如willMove)完成时,不释放堆内存。仅当没有该内存的所有者时,才会释放引用计数内存管理中的堆内存。由于存在所有权周期,因此无法释放内存。线程在这方面确实没有任何作用。如果在同一个线程上调用所有内容(实际上可能发生),则会发生相同的情况。

我认为你的主要错误是self.addChildBehavior(grav)保留grav的想法。这不是真的。它永久地将grav添加到self持有的行为列表中,这意味着创建一个强大的所有权self -> grav


0
投票

也许这会有所帮助:

Self拥有grav(作为儿童行为添加)。但grav有一个拥有self(行动)的区块。所以现在你拥有拥有selfself,这是一个保留周期。你可以在这里使用unowned self,因为如果self被释放,grav的块也将被释放。当unowned self拥有引用self的对象时,你通常在这种情况下使用self;否则,使用weak self

© www.soinside.com 2019 - 2024. All rights reserved.