views:

212

answers:

2

I've been having some trouble with Snow Leopard's new block-based API for observing notifications from NSWorkspace's NSNotificationCenter.

If I register for notifications using the traditional selector-based method, then I am able to observe the desired notification. If I try using the new method that takes a block, then it doesn't work.

In the code block below, setting usingBlockNotifications to either YES or NO should produce the same result, i.e. "didReceiveNoticationTest: called" printed to the console when an app launches, but I don't get the message when it's set to YES.

Any suggestions on what I'm doing wrong?

-(void)awakeFromNib

{

 BOOL usingBlockNotifications = YES;

 _notifcationObserver = nil;
 NSNotificationCenter *nc = [[NSWorkspace sharedWorkspace] notificationCenter];

 if (usingBlockNotifications)
 { 
  _notifcationObserver = 
  [nc addObserverForName:NSWorkspaceDidLaunchApplicationNotification
      object:[NSWorkspace sharedWorkspace]
       queue:nil
     usingBlock:^(NSNotification *arg1) {
      [self didReceiveNoticationTest:arg1];
     }];
  [_notifcationObserver retain];
 } else {
  [nc addObserver:self
      selector:@selector(didReceiveNoticationTest:)
       name:NSWorkspaceDidLaunchApplicationNotification
     object:[NSWorkspace sharedWorkspace]];
 }

}

-(void)didReceiveNoticationTest:(NSNotification *)notification
{
 NSLog(@"didReceiveNoticationTest: called");
}
+2  A: 

I daresay this is a bug.

The following code prints both notifications. If you remove the selector version, nothing is printed. If you remove the block version the selector version still prints.

-(void)didReceiveNoticationTest1:(NSNotification *)notification
{
    NSLog(@"1: didReceiveNoticationTest: called");
}
-(void)didReceiveNoticationTest2:(NSNotification *)notification
{
    NSLog(@"2: didReceiveNoticationTest: called");
}

-(void)awakeFromNib

{
    NSNotificationCenter *nc = [[NSWorkspace sharedWorkspace] notificationCenter];

    [nc addObserver:self
           selector:@selector(didReceiveNoticationTest1:)
               name:NSWorkspaceDidLaunchApplicationNotification
             object:[NSWorkspace sharedWorkspace]];

    [[nc addObserverForName:NSWorkspaceDidLaunchApplicationNotification
                     object:[NSWorkspace sharedWorkspace]
                      queue:nil
                 usingBlock:^(NSNotification* arg1)
                            {
                                [self didReceiveNoticationTest2:arg1];
                            }] retain]; // this will leak.
}
nall
Thanks for that — glad it's not just me! I've filed a bug with Apple.
Nick Hutchinson
A: 

Re-read the documentation for that method, specifically the part:

Return Value

An object or conforming to the NSObject protocol.

You must retain the returned value as long as you want the registration to exist in the notification center.

Gerd Knops
Which he does. “`[_notifcationObserver retain];`”
Peter Hosey