iosswiftautomatic-ref-countingstrong-references

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?


Solution

  • 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.