首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解在一个函数中保持循环的快速,一个例子来自马特纽堡的书

理解在一个函数中保持循环的快速,一个例子来自马特纽堡的书
EN

Stack Overflow用户
提问于 2019-02-14 18:39:32
回答 2查看 392关注 0票数 1

请考虑以下代码:

代码语言:javascript
复制
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的持久引用,gravgrav.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

我有正确的理解吗?

EN

回答 2

Stack Overflow用户

发布于 2019-02-14 19:46:20

我会尝试解释拥有权的循环,换言之:

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2019-02-14 19:14:50

也许这会有帮助:

Self拥有grav (添加为子行为)。但是grav有一个拥有self (动作)的块。所以现在有了拥有selfself,这是一个保留周期。您可以在这里使用unowned self,因为如果self被解除分配,grav的块也会使用。当self拥有引用self的对象时,通常使用unowned self;否则,使用weak self

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54697060

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档