How to pass object with NSNotificationCenter
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]?)
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)
}
}
Jon
Updated on July 08, 2022Comments
-
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 over 12 yearsThanks, 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 inviewDidLoad
isUIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];
-
Reuben Tanner over 9 yearswhy doesn't this answer have more upvotes?! it works perfectly and isn't a hack!
-
xi.lin almost 9 years@Kairos because it isn't designed to use like this. the
object
param inpostNotificationName
should meaning the one which send this notification. -
David Douglas almost 9 yearsYes 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 over 8 yearsYou 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 over 8 yearsI 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 over 7 yearsThis 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 over 7 yearsOk, thanks for the feedback... I've updated the answer to use the
userInfo
dictionary as the way to pass object's data. -
Krutarth Patel over 7 years@DavidDouglas in my case selector is not firing>
-
Lytic over 7 yearsJohan, in this simple case you are correct, but it is possible to have multiple notifications trigger the same handler
-
alpennec almost 5 yearsThanks. 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 almost 5 yearsThank you, it seems
Key
struct has been removed since then. I am updating the answer -
JRV about 2 yearsYes, it works using
object
(inNotificationCenter.default.post
call) for passing an object - however, this is not what it is meant for. Apple documentation states, thatobject
is "The object posting the notification.". UseuserInfo
instead for passing custom data (as suggested by many of the other answers on this page). -
Mussa Charles about 2 yearsHi, @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 about 2 yearsAs 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 about 2 yearsAnd here is a post concerning what the
object
parameter is actually meant for and how to use it: stackoverflow.com/questions/8779220