Clarifying the purpose of notificationSender in NSNotification's addObserver function - ios

Could someone kindly clarify the purpose of notificationSender in the addObserver function of NSNotification?
Here's the explanation from the Apple docs:
notificationSender
The object whose notifications the observer wants to receive; that is, only notifications sent by this sender are delivered to the observer.
If you pass nil, the notification center doesn’t use a notification’s sender to decide whether to deliver it to the observer.
We use notifications to respond when a video has ended. The code:
NSNotificationCenter.defaultCenter().removeObserver(self, name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem)
where playerItem contains the video in question. However, passing nil for object seems to have no discernible effect.
It's better for us to use nil instead of playerItem because we wouldn't need to create another class variable.
What's the risk in using nil, and what's the advantage in using playerItem?

The only reason to be specific with the notificationSender is if you have chosen a notification name that other objects (that you don't want to listen to) are going to send to you. Specifying a notificationSender is akin to a delegate relationship, where leaving it nil means that absolutely any object could send you a notification with the same String and you would process it.
In practice, this is rarely an issue as long as you pick notification strings that are unique. You'll see people using things like com.my.app.name.notification or kMyAppNotification for precisely this reason.
And as to the specific line of code you linked, I don't actually know the implementation details, but I'm assuming if you added a listener with the notificationSender property pointing to an object, you also need to remove the same listener with the notificationSender property set, or else risk a memory leak by not removing observers. But I'd have to read the docs again to figure that out.

Related

What does post to notification center mean

What is to post to notification center mean?
What is the difference between to post and to add observer using NotificationCenter.
NSNotificationCenter : NSNotificationCenter can be consider as an interface used for communicating information within your app.Unlike push or local notifications where you are notifying a user of any content you would like them to receive, NSNotificationCenter allows us to send and receive information between classes and/or structs based on an action that has occurred in our app. NotificationCenter simply can be thought of an broadcaster and we tune into some stations/channels to receive the changes if any.
NotificationCenter.default is where all the notifications are observed and posted.Each notification has a unique identifier which can be used to validate the channel at broadcasting end as well as receiving end.
addObserver() : Objects register with a notification center to receive notifications using the addObserver(_:selector:name:object:) or addObserver(forName:object:queue:using:) methods. When an object adds itself as an observer, it specifies which notifications it should receive. An object may therefore call this method several times in order to register itself as an observer for several different notifications.The class implementing the addobserver() method is reciever.
Example : Adding an observer(this is will at the receiving end)
NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
#objc func methodOfReceivedNotification(notification: Notification){}
post() : Creates a notification with a given name and sender and posts it to the notification center. Creating a package and send it through the channel. The class implementing the post() method is broadcaster.
Example : Posting an observer(this is will at the broadcasting end)
NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)
Note that the "NotificationIdentifier" is the unique name to identify the particular channel. And selector is method/action that need to be performed when a notification is received.You can also pass the data within the notification center within the "object" parameter.
"With respect to your question "What is the difference between to post and to add observer using NotificationCenter."
The answer is they both go head to head, one (add-observer()) is used to send and another one (post()) is used to receive. so if you are posting a notification its must that you should implement an observer too.In short if you throw something you need someone to catch, if you speak, you need someone to listen.
Simply notification center used to post information to registered observer
Information about NotificationCenter
Example

NS Notification Confused Swift 3

Currently in the process of implementing NS Notification in to my first IOS application. I am wanting to use it so when a user succesfully makes a purchase, the product name is broad cast out, and the listener runs the method to unlock the products. Looking at tutorials i am confused about how it works and would really appreciate if these could be cleared up. I will post the code below and what i think it does, if their are any mistakes please point these out.
Line 1 - Let is a variable that can not be changed, NotificationName is the name of the variable. Notfication.Name is declaring the name as "Notification Identifier"
let notificationName = Notification.Name("NotificationIdentifier")
Line 2 - I think here the "NotificationName" is the id of this for the listener as defined above by the let.
If i want to pass in an object is this done at the end? via the object tag. IE object: productsRequest
NotificationCenter.default.post(name: notificationName, object: nil)
Line - 3 This is the listener, the notification name has to match the post to receive the correct notification i assume. The add observer self selector is confusing me, and if i pass in an object from the post line 2 above, ie Object Products Request. Does this have to be declared in the listener?
NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification), name: notificationName, object: nil)
Any explanations to further my understanding are appreciated. Sorry if these seems like a basic question, how ever reading tutorials i am struggling to understand certain elements of this.
Thanks
Correct.
Correct. The object you pass into postNotification method is a sender, which can be used to filter notifications with the same name (p.3)
When you subscribe for a specific notification and pass an object to addObserver method, you will receive only notifications which were sent with this exact object. If you don't specify it in addObserver you will receive all notifications with this name.
Don't forget to removeObserver as soon as you don't need to listen to them anymore. If your listener is a view controller, it is usually a good practice to addObserver in viewWillAppear and removeObserver in viewDidDisappear methods.

Is it dangerous to directly pass object via [[NSNotificationCenter defaultCenter] postNotificationName] method?

I am writting an SDK and looking for the best practise to send an object via NSNotification.
Apple and some threads including this indicate that the object param in postNotificationNamer should be the sender of the notification, which in most case, self. And your custom object should be passed via userInfo NSDictionary. From Apple doc:
Creates a notification with a given name, sender, and information and posts it to the receiver.
For example, the inappropriate practise is:
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification"
object:myObject];
And the recommended way is:
NSDictionary* userInfo = #{#"myMessage": myObject};
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification"
object:self
userInfo:userInfo];
I have tried both methods and they all work well. Question is, is there any risk to use former method? In my case I am not interested in the sender of the notification, but using the latter method introduces an additional wrapper (NSDicionary) around the actual object I want to send.
It's not dangerous to use the object parameter, but have in mind that NSNotificationCenter uses that parameter internally to decide some things. So if your code depends on things running in certain order or certain queues, it may behave unexpectedly.
Here's the relevant quote from the NSNotificationCenter Class Reference:
The object whose notifications you want to add the block to the operation queue.
If you pass nil, the notification center doesn’t use a notification’s sender to decide whether to add the block to the operation queue.
I would recommend that you used userInfo as intended, but it is not dangerous.
The latter is more flexible. While you may not care about the sender now, that could change. And you may later find you need to pass additional info.
Better to do it right upfront. It takes no extra effort to do it right the first time and it will be a lot of effort (and prone to mistakes) to have to go back and refactor a bunch of code when your needs change.
Plus, using the latter approach means your code is consistent with how it is done in other frameworks. Consistency makes code easier to read and maintain. You don't have to think about, "well in this case I get the object here, but in this case I get it there".

How to retrieve all NSNotificationCenter observers?

I'd like to retrieve a list of observers (objects and selectors) for a given notification name. I know there's no official API for that. I also know I could subclass NSNotificationCenter to accomplish this. Sometimes however this is not a viable option because NSNotificationCenter usage is spread all over the code or even binary frameworks.
So I'm looking for an unofficial/private way to do this. (Since it's about debugging only, that's fine.)
Finally, Apple added a way to print all notification center observers:
po [NSNotificationCenter defaultCenter]
It prints a comma separated list with Name, Object, Observer, and Options:
<NSNotificationCenter:0x7f997b307500>
Name, Object, Observer, Options
WebPreferencesRemovedNotification, 0x11165b680, 0x116c87ff8, 1400
UIApplicationWillEnterForegroundNotification, 0x11165b680, 0x7f997a838000, 1400
...
If you don't want to subclass NSNotificationCenter you can rename original addObserver:selector:name:object method and create your own with such name and add observers in there to some array then call original renamed method.
Take a look at following methods: class_addMethod, class_replaceMethod, class_getMethodImplementation.
Also look at this SO question: Method Swizzling
I am not sure why you want observers but you might find this class useful, which removes observers automatically for you which I think might be what you want. SFObservers

Removing all notification observer from a single place

I want to remove a notification observer and I am using the method:
[[NSNotificationCenter defaultCenter] removeObserver: name:#"myNotification" object:nil];
for this. Now there are many observers who are listening to this notification and I want to remove all of them in one shot from a centralised place. Can I pass 'nil' in first parameter and it will remove all observers who are listening to myNotification?
You can remove an object from the notification center all together which means no notifications will get triggered. For example, when I have a view controller that has registered for notifications, I include this line in my dealloc.
[[NSNotificationCenter defaultCenter] removeObserver:self];
This is at the object level...so it will unregister for many notifications. It won't unregister for one notification in many objects.
Hope I understood your question correctly.
In case of Swift, you doing it like this:
NSNotificationCenter.defaultCenter().removeObserver(self)
And in Swift 3:
NotificationCenter.default.removeObserver(self)
Unfortunately, there is no way to remove all observers of a specific notification in one place. While there are certainly cases where this would be nice, it would be a dangerous thing to do as generally, the object doing the observing should be responsible for adding and removing itself as an observer of a particular notification. This ensures no unpredictable behavior b/c observers can come and go so they configure and clean up after themselves.
If an object that generates notifications goes away, it won't matter to the observer as the observer doesn't know about that object anyway. It just means that object won't be generating any more notifications.
[EDIT: RESPONSE TO YOUR COMMENT RE CLASS B STOPPING CLASS A FROM OBSERVING]
I just saw your comment. There are different ways to accomplish this, particularly if class B knows about class A. As you reference classes it sounds like you want to affect all instances of a class vs a particular instance. If you have some condition you can check when handling the notification, that's how I would approach this. In the notification handler something like:
if ([self shouldRespondToNotificationNamed:notification.name]) {
[self performNotificationAction];
}
If you don't have a condition you can check, then create one either in the class in question as an iVar or in a place where you can access it globally for all class instances. I generally use a singleton to store global app state that doesn't persist. If it persists, then use whatever method you're using for other state.

Resources