633

I am attempting to send and receive messages through NSNotificationCenter in Objective-C. However, I haven't been able to find any examples on how to do this. How do you send and receive messages through NSNotificationCenter?

7
  • Really very useful, thanks. One thing, the addObserver method shouldn't have the trailing semi colon after the specified selector (at least it caused an exception in my version of this). I tried editing the code above but the change was not accepted due to formatting issues in the original code.
    – Braunius
    Oct 5, 2011 at 8:02
  • 3
    This was great: cocoawithlove.com/2008/06/… Feb 13, 2012 at 5:35
  • 2
    this q is way too basic and broad, a little googleing would have beeen good
    – Daij-Djan
    Nov 14, 2012 at 7:52
  • This is very similar to a related question here: stackoverflow.com/questions/7896646/… Jun 21, 2014 at 9:49
  • 59
    I find it absurd a question like this is closed an not constructive when the users of Stack Overflow have so clearly commented its usefulness
    – Chet
    Jul 31, 2014 at 1:06

6 Answers 6

1041
@implementation TestClass

- (void) dealloc
{
    // If you don't remove yourself as an observer, the Notification Center
    // will continue to try and send notification objects to the deallocated
    // object.
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

- (id) init
{
    self = [super init];
    if (!self) return nil;

    // Add this instance of TestClass as an observer of the TestNotification.
    // We tell the notification center to inform us of "TestNotification"
    // notifications using the receiveTestNotification: selector. By
    // specifying object:nil, we tell the notification center that we are not
    // interested in who posted the notification. If you provided an actual
    // object rather than nil, the notification center will only notify you
    // when the notification was posted by that particular object.

    [[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(receiveTestNotification:) 
        name:@"TestNotification"
        object:nil];

    return self;
}

- (void) receiveTestNotification:(NSNotification *) notification
{
    // [notification name] should always be @"TestNotification"
    // unless you use this method for observation of other notifications
    // as well.

    if ([[notification name] isEqualToString:@"TestNotification"])
        NSLog (@"Successfully received the test notification!");
}

@end

... somewhere else in another class ...

- (void) someMethod
{

    // All instances of TestClass will be notified
    [[NSNotificationCenter defaultCenter] 
        postNotificationName:@"TestNotification" 
        object:self];

}
15
  • 2
    Just wondering where [NSNotificationCenter defaultCenter] is meant to placed. Is it best to place it in your AppDelegate?
    – gotnull
    Jan 12, 2011 at 6:17
  • 15
    @Fulvio: It depends, if you are receiving or posting notifications that potentially affect all parts of your application, put it in your AppDelegate. If you are receiving/posting notifications that only affect a single class, put it in that class instead.
    – dreamlax
    Jan 12, 2011 at 8:34
  • 1
    @dreamlax Truth, however it's worth noticing because this question is mostly searched by new ios devs who keep the notification listener alive longer than they need. Now with arc you usually don't use dealloc and as a result some may think they don't have to release the listener.
    – Nat
    Nov 5, 2013 at 7:45
  • 8
    It might also be worth mentioning that the [super dealloc] call in the dealloc-method is not permitted under ARC; the rest is all good.
    – tommys
    Feb 19, 2014 at 18:02
  • 1
    What happen if the notification fires and there are no observers? Is notification lost? Or is it "saved" somewhere ready to be shipped to a new observer (created later)? Feb 27, 2015 at 12:19
237

To expand upon dreamlax's example... If you want to send data along with the notification

In posting code:

NSDictionary *userInfo = 
[NSDictionary dictionaryWithObject:myObject forKey:@"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName: 
                       @"TestNotification" object:nil userInfo:userInfo];

In observing code:

- (void) receiveTestNotification:(NSNotification *) notification {

    NSDictionary *userInfo = notification.userInfo;
    MyObject *myObject = [userInfo objectForKey:@"someKey"];
}
9
  • TestNotification must be NSString type. Is it an instance variable NSNotification?
    – RomanHouse
    May 2, 2012 at 18:50
  • 1
    Can I access observer self in receiveTestNotification method ?
    – why
    Feb 26, 2013 at 9:08
  • why - Yes. receiveTestNotification is an instance method, and you have access to the instance itself via self within it. Aug 1, 2014 at 22:01
  • That's it. I was looking for a way to get the UserInfo from the receiver method.
    – hasan
    Jan 14, 2015 at 11:58
  • It seems that all that observer idea doesn't cover all cases. this didn't work when the app. was closed and a notification form the notification centre got tapped. observer method doesn't get called.
    – hasan
    Jan 14, 2015 at 12:26
52

This one helped me:

// Add an observer that will respond to loginComplete
[[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(showMainMenu:) 
                                                 name:@"loginComplete" object:nil];


// Post a notification to loginComplete
[[NSNotificationCenter defaultCenter] postNotificationName:@"loginComplete" object:nil];


// the function specified in the same class where we defined the addObserver
- (void)showMainMenu:(NSNotification *)note {
    NSLog(@"Received Notification - Someone seems to have logged in"); 
}

Source: http://www.smipple.net/snippet/Sounden/Simple%20NSNotificationCenter%20example

0
52

There is also the possibility of using blocks:

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[[NSNotificationCenter defaultCenter] 
     addObserverForName:@"notificationName" 
     object:nil
     queue:mainQueue
     usingBlock:^(NSNotification *notification)
     {
          NSLog(@"Notification received!");
          NSDictionary *userInfo = notification.userInfo;

          // ...
     }];

Apple's documentation

2
  • 1
    This is a good update to my answer which is fairly outdated now. With the introduction or ARC and blocks, notification centres are much easier to deal with.
    – dreamlax
    Apr 24, 2013 at 17:14
  • 5
    I thought so too, but it turns out that it's too good to be true. In this case you have to retain the observer that addObserver returns and later on remove that, which makes it as complicated as creating a new method, if not more so. More info: toastmo.com/blog/2012/12/04/…
    – Andrew
    Aug 27, 2013 at 12:34
43

if you're using NSNotificationCenter for updating your view, don't forget to send it from the main thread by calling dispatch_async:

dispatch_async(dispatch_get_main_queue(),^{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"my_notification" object:nil];
});
3
  • 1
    is it the notification post that needs to occur from the main thread, or just when you actually update the view, i.e., inside the method receiving the notification you dispatch to the main thread?
    – Crashalot
    Apr 19, 2016 at 4:46
  • 1
    the thread you send the notification from is the thread running the functions, and thus trying to change the UI. you can also use the dispatch to the main thread inside the functions, just like you said:D. should have the same result, perheps it's even better:D
    – eiran
    Apr 19, 2016 at 9:29
  • 1
    @eiran, thank you so much bro, it worked only after i wrote inside dispatch_async Aug 6, 2019 at 6:49
8

SWIFT 5.1 of selected answer for newbies

class TestClass {
    deinit {
        // If you don't remove yourself as an observer, the Notification Center
        // will continue to try and send notification objects to the deallocated
        // object.
        NotificationCenter.default.removeObserver(self)
    }

    init() {
        super.init()

        // Add this instance of TestClass as an observer of the TestNotification.
        // We tell the notification center to inform us of "TestNotification"
        // notifications using the receiveTestNotification: selector. By
        // specifying object:nil, we tell the notification center that we are not
        // interested in who posted the notification. If you provided an actual
        // object rather than nil, the notification center will only notify you
        // when the notification was posted by that particular object.

        NotificationCenter.default.addObserver(self, selector: #selector(receiveTest(_:)), name: NSNotification.Name("TestNotification"), object: nil)
    }

    @objc func receiveTest(_ notification: Notification?) {
        // [notification name] should always be @"TestNotification"
        // unless you use this method for observation of other notifications
        // as well.

        if notification?.name.isEqual(toString: "TestNotification") != nil {
            print("Successfully received the test notification!")
        }
    }
}

... somewhere else in another class ...

 func someMethod(){
        // All instances of TestClass will be notified
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "TestNotification"), object: self)
 }