Benedict's Soapbox

A Valid Use Case for addObserverForName:

NSNotificationCenter’s block based addObserverForName: has frequently been highlighted as a poor use of blocks. Brent Simmons explains why in How Not to Crash #3: NSNotification. In general I agree with Brent’s assessment and believe that the traditional addObserver: method results in more readable and more crash proof code. But there is one small exception when I think addObserverForName: is preferable which is when you need to observe related notifications that occur sequentially, for example MPMoviePlayerWillExitFullscreenNotification and MPMoviePlayerDidExitFullscreenNotification. There are 2 benefit to this technique. Firstly, it’s easier to see the relationship between the code of the handlers and secondly the scope of the state that’s shared between the notification handlers is smaller than if we’d used addObserver:. There are only a few of these paired notifications in OS X and even fewer in iOS so this isn’t a technique you’ll need often.

Here’s an example of how to use add addObserverForName: for paired notifications:

-(instancetype)init
{
   ...
   //Register for the 'will' notification as usual.
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayerWillExitFullScreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
   ...
}

-(void)dealloc
{
    ...
    //Unregister as usual
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    ...
}

-(void)moviePlayerWillExitFullScreen:(NSNotification *)willNotification
{
    id preTransitionTransientState = ...;
    //Create a one-shot 'did' observer. Note the storage modifiers of block and weak.
   __weak __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:MPMoviePlayerDidExitFullscreenNotification object:notification.object queue:nil usingBlock:^(NSNotification *didNotification) {
        [[NSNotificationCenter defaultCenter] removeObserver:observer]; //Unregister the 'did' observer.
       id postTransitionTransientState = ...;           
       [self aMethodThatTakesPreState:preTransitionTransientState postState:postTransitionTransientState];
    }];
}