为什么 NSNotificationCenter 可以实现强引用循环而不是 UIView.animateWithDuration?

Why is a strong reference cycle possible with NSNotificationCenter but not UIView.animateWithDuration?

对于 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()
   })

有什么区别?

UIView 动画的 animations: () -> Voidcompletion: ((Bool) -> Void)? 块不保留对自身的引用。之前的 post 对主题

提供了很多信息


通知块 (NSNotification) -> Void 确实保留了对自身的引用,在您的情况下将其作为无主传递,它不应增加保留计数。我尽量确保我在传递给闭包的任何引用上使用 unowned 或 weak。在这里 http://krakendev.io/blog/weak-and-unowned-references-in-swift

找到了一个很棒的 post


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

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

动画块和通知中心块的唯一区别是动画块的生命周期极短——立即执行然后释放。

在这两种情况下,块将捕获 self;但只有 NSNotificationCenter 代码有问题,因为通知中心将无限期地持有对该块的引用,因为通知可能随时发生。

请注意,这与循环引用不同。循环引用通常由持有对捕获自身的块的引用的对象创建,如下所示:

self.myBlock = {
   self.doSomething()
}

循环引用意味着 self 永远不会被释放。通知中心不是循环引用(因为 self 不持有对通知中心的引用),它只是一个常规引用​​,将一直保留到观察者被移除。