Question

The design pattern below appears a few times in my app. I'm in the midst of converting to ARC. Can someone corroborate whether __unsafe_retained __block is correct usage?

__unsafe_unretained __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:MyNotification 
    object:nil 
    queue:nil 
    usingBlock:^(NSNotification *note) {
        [[NSNotificationCenter defaultCenter] removeObserver:observer];
        // ...
    }];

Some notes:

  • __unsafe_unretained is used because deployment target is 10.6
  • __block is used because otherwise observer would be captured by the block prematurely
  • Xcode's ARC migration tool added __unsafe_unretained for me. Is it necessary? I realize that without it the block will retain observer, but is that so bad? Would it lead to a retain cycle?
Was it helpful?

Solution

The question of whether __unsafe_unretained is needed comes down to whether there would be a retain cycle otherwise. We know that if it were a strong reference, then the block would retain observer. The question then is, does observer retain the block (or even, may it be the block itself)?

This is a question that cannot be answered from first principles. It requires knowing what the observer object is and what it does internally. Unfortunately, this is an opaque object that Apple does not tell us much about, other than that we must use it to remove the observer. The documentation does not say anything about what this object is or may retain internally. I believe this is a serious omission from the documentation.

From other StackOverflow answers, e.g. this and this, it appears empirically that if a weak reference (__weak or __unsafe_unretained) from the block to the observer is not used, a retain cycle results. Therefore, we can conclude that the observer object retains (or, is) the block.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top