TruMan1 TruMan1 - 4 months ago 20
Swift Question

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

With a NSNotificationCenter block, I have to use [unowned self] to avoid a strong reference cycle:

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


However, in UIView.animateWithDuration, I do not have to use [unowned self]:

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


What's the difference?

Answer

The only difference between the animation block and the notification center block is that the animation block is extremely short-lived—it is executed immediately and then released.

In both cases, the blocks will capture self; but only the NSNotificationCenter code is problematic because the notification center will hold a reference to the block indefinitely, since the notification can happen at any time.

Note that this is different than a circular reference. A circular reference is often created by an object holding a reference to a block that captures self, like this:

self.myBlock = {
   self.doSomething()
}

That circular reference means that self will never be deallocated. The notification center isn't a circular reference (since self doesn't hold a reference to the notification center), it's just a regular reference that will be held until the observer is removed.