How to pass object with NSNotificationCenter

119,068

Solution 1

You'll have to use the "userInfo" variant and pass a NSDictionary object that contains the messageTotal integer:

NSDictionary* userInfo = @{@"total": @(messageTotal)};

NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:@"eRXReceived" object:self userInfo:userInfo];

On the receiving end you can access the userInfo dictionary as follows:

-(void) receiveTestNotification:(NSNotification*)notification
{
    if ([notification.name isEqualToString:@"TestNotification"])
    {
        NSDictionary* userInfo = notification.userInfo;
        NSNumber* total = (NSNumber*)userInfo[@"total"];
        NSLog (@"Successfully received test notification! %i", total.intValue);
    }
}

Solution 2

Building on the solution provided I thought it might be helpful to show an example passing your own custom data object (which I've referenced here as 'message' as per question).

Class A (sender):

YourDataObject *message = [[YourDataObject alloc] init];
// set your message properties
NSDictionary *dict = [NSDictionary dictionaryWithObject:message forKey:@"message"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationMessageEvent" object:nil userInfo:dict];

Class B (receiver):

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter]
     addObserver:self selector:@selector(triggerAction:) name:@"NotificationMessageEvent" object:nil];
}

#pragma mark - Notification
-(void) triggerAction:(NSNotification *) notification
{
    NSDictionary *dict = notification.userInfo;
    YourDataObject *message = [dict valueForKey:@"message"];
    if (message != nil) {
        // do stuff here with your message data
    }
}

Solution 3

Swift 5

func post() {
    NotificationCenter.default.post(name: Notification.Name("SomeNotificationName"), 
        object: nil, 
        userInfo:["key0": "value", "key1": 1234])
}

func addObservers() {
    NotificationCenter.default.addObserver(self, 
        selector: #selector(someMethod), 
        name: Notification.Name("SomeNotificationName"), 
        object: nil)
}

@objc func someMethod(_ notification: Notification) {
    let info0 = notification.userInfo?["key0"]
    let info1 = notification.userInfo?["key1"]
}

Bonus (that you should definitely do!) :

Replace Notification.Name("SomeNotificationName") with .someNotificationName:

extension Notification.Name {
    static let someNotificationName = Notification.Name("SomeNotificationName")
}

Replace "key0" and "key1" with Notification.Key.key0 and Notification.Key.key1:

extension Notification {
  enum Key: String {
    case key0
    case key1
  }
}

Why should I definitely do this ? To avoid costly typo errors, enjoy renaming, enjoy find usage etc...

Solution 4

Swift 2 Version

As @Johan Karlsson pointed out... I was doing it wrong. Here's the proper way to send and receive information with NSNotificationCenter.

First, we look at the initializer for postNotificationName:

init(name name: String,
   object object: AnyObject?,
 userInfo userInfo: [NSObject : AnyObject]?)

source

We'll be passing our information using the userInfo param. The [NSObject : AnyObject] type is a hold-over from Objective-C. So, in Swift land, all we need to do is pass in a Swift dictionary that has keys that are derived from NSObject and values which can be AnyObject.

With that knowledge we create a dictionary which we'll pass into the object parameter:

 var userInfo = [String:String]()
 userInfo["UserName"] = "Dan"
 userInfo["Something"] = "Could be any object including a custom Type."

Then we pass the dictionary into our object parameter.

Sender

NSNotificationCenter.defaultCenter()
    .postNotificationName("myCustomId", object: nil, userInfo: userInfo)

Receiver Class

First we need to make sure our class is observing for the notification

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("btnClicked:"), name: "myCustomId", object: nil)   
}
    

Then we can receive our dictionary:

func btnClicked(notification: NSNotification) {
   let userInfo : [String:String!] = notification.userInfo as! [String:String!]
   let name = userInfo["UserName"]
   print(name)
}

Solution 5

Swift 5.1 Custom Object/Type

// MARK: - NotificationName
// Extending notification name to avoid string errors.
extension Notification.Name {
    static let yourNotificationName = Notification.Name("yourNotificationName")
}


// MARK: - CustomObject
class YourCustomObject {
    // Any stuffs you would like to set in your custom object as always.
    init() {}
}

// MARK: - Notification Sender Class
class NotificatioSenderClass {

     // Just grab the content of this function and put it to your function responsible for triggering a notification.
    func postNotification(){
        // Note: - This is the important part pass your object instance as object parameter.
        let yourObjectInstance = YourCustomObject()
        NotificationCenter.default.post(name: .yourNotificationName, object: yourObjectInstance)
    }
}

// MARK: -Notification  Receiver class
class NotificationReceiverClass: UIViewController {
    // MARK: - ViewController Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        // Register your notification listener
        NotificationCenter.default.addObserver(self, selector: #selector(didReceiveNotificationWithCustomObject), name: .yourNotificationName, object: nil)
    }

    // MARK: - Helpers
    @objc private func didReceiveNotificationWithCustomObject(notification: Notification){
        // Important: - Grab your custom object here by casting the notification object.
        guard let yourPassedObject = notification.object as? YourCustomObject else {return}
        // That's it now you can use your custom object
        //
        //

    }
      // MARK: - Deinit
  deinit {
      // Save your memory by releasing notification listener
      NotificationCenter.default.removeObserver(self, name: .yourNotificationName, object: nil)
    }




}

Share:
119,068
Jon
Author by

Jon

Updated on July 08, 2022

Comments

  • Jon
    Jon almost 2 years

    I am trying to pass an object from my app delegate to a notification receiver in another class.

    I want to pass integer messageTotal. Right now I have:

    In Receiver:

    - (void) receiveTestNotification:(NSNotification *) notification
    {
        if ([[notification name] isEqualToString:@"TestNotification"])
            NSLog (@"Successfully received the test notification!");
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissSheet) name:UIApplicationWillResignActiveNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveTestNotification:) name:@"eRXReceived" object:nil];
    

    In the class that is doing the notification:

    [UIApplication sharedApplication].applicationIconBadgeNumber = messageTotal;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"eRXReceived" object:self];
    

    But I want to pass the object messageTotal to the other class.

  • Jon
    Jon over 12 years
    Thanks, I'm setting messageTotal to a badge on a UIButton, do you know how I can refresh the button with the new badge count? The code to display the image in viewDidLoad is UIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];
  • Reuben Tanner
    Reuben Tanner over 9 years
    why doesn't this answer have more upvotes?! it works perfectly and isn't a hack!
  • xi.lin
    xi.lin almost 9 years
    @Kairos because it isn't designed to use like this. the object param in postNotificationName should meaning the one which send this notification.
  • David Douglas
    David Douglas almost 9 years
    Yes the object should be passed as an NSDictionary using the userInfo param and the accepted answer above has now been edited to show this.
  • Johan Karlsson
    Johan Karlsson over 8 years
    You are actually violating the intended use of the postNotificationName(). But you are not alone. I have seen many developer using the object parameter for sending user objects. The second argument, the object, is reserved for the sender. You should really user the userInfo to send all kind of objects. Otherwise you might encounter random crashes etc.
  • Johan Karlsson
    Johan Karlsson over 8 years
    I am not sure why you need to compare the notification.name. The mapping of the name should be performed when you do the addObserver(). The receiveTestNotification should only be called when observing a specific notification.
  • Shinnyx
    Shinnyx over 7 years
    This is very misleading, why does that answer has so many upvotes? This should be deleted. Everyone should use userInfo which was created exactly for this.
  • David Douglas
    David Douglas over 7 years
    Ok, thanks for the feedback... I've updated the answer to use the userInfo dictionary as the way to pass object's data.
  • Krutarth Patel
    Krutarth Patel over 7 years
    @DavidDouglas in my case selector is not firing>
  • Lytic
    Lytic over 7 years
    Johan, in this simple case you are correct, but it is possible to have multiple notifications trigger the same handler
  • alpennec
    alpennec almost 5 years
    Thanks. Apparently extending Notification.Name is possible but not Notification.Key. 'Key' is not a member type of 'Notification'. See here: https://ibb.co/hDQYbd2
  • frouo
    frouo almost 5 years
    Thank you, it seems Key struct has been removed since then. I am updating the answer
  • JRV
    JRV about 2 years
    Yes, it works using object (in NotificationCenter.default.post call) for passing an object - however, this is not what it is meant for. Apple documentation states, that object is "The object posting the notification.". Use userInfo instead for passing custom data (as suggested by many of the other answers on this page).
  • Mussa Charles
    Mussa Charles about 2 years
    Hi, @JRV, Thanks for the insights, I used this implementation on my app back then so far no problem with it. Would you mind clarifying what problems or side effects could occur as a result of using my implementation above? It will be very helpful if you can attach supporting test code.
  • JRV
    JRV about 2 years
    As I wrote, it will work, and I have actually done the same myself - until I read Apple's documentation more carefully 🙈. And I would not recommend working against Apple's own documentation as it can lead to unexpected results in a future implementation of NSNotificationCenter. Here is a SO post that concerns your specific question: stackoverflow.com/questions/33635445
  • JRV
    JRV about 2 years
    And here is a post concerning what the object parameter is actually meant for and how to use it: stackoverflow.com/questions/8779220