为什么NSNotificationCenter可以产生强引用循环,而UIView.animateWithDuration却不行?

3

使用NSNotificationCenter块时,我必须使用[unowned self]来避免强引用循环:

NSNotificationCenter.defaultCenter()
    .addObserverForName(UIApplicationWillEnterForegroundNotification,
        object: nil,
        queue: nil,
        usingBlock: { [unowned self] (notification : NSNotification!) -> Void in
            self.add(123)
        })

然而,在UIView.animateWithDuration中,我不需要使用[unowned self]:

   UIView.animateWithDuration(0.5, animations: { () -> Void in
      self.someOutlet.alpha = 1.0
      self.someMethod()
   })

有什么区别?

2个回答

6
动画块和通知中心块之间唯一的区别是动画块的生命非常短暂——它立即执行并释放。
两种情况下,块都会捕获self;但只有NSNotificationCenter代码存在问题,因为通知中心将无限期地持有对块的引用,因为通知可以随时发生。
请注意,这与循环引用不同。循环引用通常由一个对象持有对捕获self的块的引用而创建,就像这样:
self.myBlock = {
   self.doSomething()
}

那个循环引用意味着self永远不会被释放。通知中心不是循环引用(因为self没有对通知中心的引用),它只是一个普通的引用,在观察者被移除之前一直保持。

1

animations: () -> Voidcompletion: ((Bool) -> Void)?是UIView Animation中的块,它们不会保留对self的引用。这篇先前的文章非常详细地讨论了这个问题。

我们在ARC中需要在UIAnimationBlocks内使用__weak self吗?


通知块(NSNotification) -> Void通过将其作为未拥有的传递而保留对self的引用,在您的情况下,它不应增加保留计数。我尝试确保在我传递到闭包中的任何引用上使用unowned或weak。这里有一篇很棒的文章http://krakendev.io/blog/weak-and-unowned-references-in-swift可以了解更多信息。


但是,我强烈建议不要使用通知,特别是与块一起使用,因为这篇文章指出可能存在一个错误,当我读到它时感到震惊。

http://sealedabstract.com/code/nsnotificationcenter-with-blocks-considered-harmful/


哇,这太疯狂了,所以只是因为Cocoa的一个bug我才不得不这样做? - TruMan1
@TruMan1 我提供的答案只是强调了通知中心的一个问题。真正的原因是你想避免创建强引用循环,我更新了我的答案以反映这一点。 - AntonTheDev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接