I am learning how to use NSNotificationCenter. My understanding is that for each notification, you can send a single object. Is there a way to send a notification with multiple objects or must I post a new notification for each object?
You can pass any information you like in the userInfo argument of postNotification:object:userInfo:.
For example, you could call the method as follows:
NSDictionary *accountDetails = #{#"accountHolder":#"Mr John Smith",
#"accountNumber":#(01234567),
#"sortCode":#"01-98-34"};
[[NSNotificationCenter defaultCenter] postNotificationName:#"BankDidCreateNewAccount" object:self userInfo:accountDetails];
Just to explain in more detail: to post notifications with an object, you'd use either
-postNotificationName:object: or -postNotificationName:object:userInfo:
In the object argument, you may only supply a single object. Typically, the object argument is the notificationSender, i.e. you would pass self from wherever you post the notification.
If you have registered for notifications using -addObserver:selector:name:object:, and you passed any value but nil for the object argument, then you will only receive notifications where the posted notification object (object argument in -postNotificationName:object:) matches the the object argument in -addObserver:.
If you pass nil in -addObserver: then the object value of -postNotification: is ignored for this particular observer.
Wow, that sounds complicated. But it's actually very simple. object argument must match if used in -addObserver:.
Use userInfo argument to supply more details to the notification observer.
A notification can only have one object. For multiple objects it depends what you want to send them for. If each is being observed separately then yes, you need to send multiple notifications. If you just need to send context info then you should use userInfo.
Related
Consider something like the following example:
I have a library with books, books have a difficulty and genre.
Each book is an instance of some object and could be presented by a view controller (I.E. a collection view, where each cell is a book, of perhaps a detail view where only one book is displayed).
The data of these books can be updated in the background by some kind of synchronisation method. It is possible only one book is updated, or perhaps one genre.
I would like the classes (mostly the views) to receive a notification of updates. I would like these notifications to be pretty clear. So when all non-fiction books are updated this is what should be notified.
I could of course use separate notification names for each kind, but if we are talking about an entire library, a big collection view containing thousands of objects would mean registering too many observers. In this case the observer would perhaps choose to receive any notification on books, of maybe any of a genre.
What I am missing (or can't seem to figure out) in NSNotification is some kind of granularity to specify this need.
So in short:
Is there a way to tell NSNotification more specifically what kind of notifications I would like to receive/who to send it to?
Alternatively, can I attach an object to a notification? If so, I could model scope (like meta-data) of the notification in this object and let the receiver check this data.
Yes , you can do that, just specify your object and pack your meta-data in an dictionary and attach your notification as userInfo.and use this method to post notification :
- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo
then you can access your notification like :
- (void)handleNotification:(NSNotification *)noti{
NSDictionary *userInfo = [noti userInfo];
YourObject *object = [noti object];
}
I'm trying to understand this two parameters of the method but i don't seems to understand it.
addObserverForName:object:queue:usingBlock:
I don't understand the description of 2 of the parameters in the method. Hope someone can explain it to me.
- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *))block
I don't understand this 2 lines:
name
The name of the notification for which to register the observer; that is, only notifications with this name are used to add the block to the operation queue.
If you pass nil, the notification center doesn’t use a notification’s name to decide whether to add the block to the operation queue.
what does it mean when the notification centre doesn't use notification name to decide whether to add block to the operation queue when it is nilled.
also,what notification name should i put in. I don't know.
and
obj
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.
What object should i insert into this parameters.
nil name and valid object - all notifications from that object will be passed to the block.
Valid name and nil object, all notifications of that name by any object will be passed to the block.
Valid name and valid object - notifications of that name by that object will be passed to the block.
The name of the notification depends on what notification you want to observe, we can't tell you what to use from the description of your problem as it stands.
The documentation for the description of the name parameter sounds like it was copy-and-pasted from the description of object.
Notifications are sent with a string notification name:
[[NSNotificationCenter defaultCenter] postNotificationName: #"somethingHappened"
object: self];
Usually, but not always, the "object" in the post notification call is the object that is posting the notification. It might also be the object that the notification is about:
[[NSNotificationCenter defaultCenter] postNotificationName: #"aHouseCaughtFire"
object: theHouseThatCaughtFire];
That post notification call sends a message (e.g. "aHouseCaughtFire"), and the object parameter tells what object the event was associated with.
When you register for a notification, you can say that you care about a specific notification string (name), a particular object, or both. As the other poster said, if you pass in a nil notification name and a non-nil object, you'll be notified about all notifications sent with the object parameter you specified.
If you are going on vacation, you might want to register about all notifications regarding your house. (notification = nil, object = your house.)
Thus, you'd get "aHouseCaughtFire" notifications, "aHouseWasRobbed" notifications, and "aHouseGotaAPackage" notifications about your house, but not notifications about other houses.
If you are a fire department, you might want to register for all "aHouseCaughtFire" notifications, regardless of which house it is. Then the notification handler would look up the address of the specific house, and dispatch a fire truck.
I want my NSManagedObject to listen for a notification from a timer class that will post an NSnotification every second. This is needed to update a value in my NSManagedObject.
Problem is as the CD lifecycle is out of my control it appears that i'm getting duplicate NSNotifications which I have found out is due to the multiple contexts that a NSManagedObject could be in.
How canI listen for this notification reliably inside my NSManagedObject?
This is a normal side effect of the way Core Data works. You're creating multiple objects that represent the same underlying data. All of them are registering for the same notification, so all of them get it. Listening for a notification like this is not a very good idea, because this duplication is a fundamental part of how the system works.
If the objects that should respond to the notification all come from the same managed object context, there are workarounds. For example, to listen for the notification only if the object was fetched from the root context in a parent/child context setup, do something like
if ([[self managedObjectContext] parentContext] == nil) {
...register for notification
}
If you don't use parent/child context relationships, you could decide that one specific context is "the one" whose managed objects get the notification, and compare [self managedObjectContext] to that.
A better solution would be to sidestep the problem and listen for the notification somewhere else-- or else just update the value from the timer callback, without using a notification. Whenever the timer fires, update the value on one specific instance of the object. This way you'll know that you're making the change in exactly one place, on one object. Other instances from other contexts would need to merge the change to get the new value.
I use Core Data - and I have registered and is listening for NSManagedObjectContextDidSaveNotification:s I have a collection of data (from JSON), that I want to save, and after all objects is saved, I would like to get some kind of notification. It currently seems like this notification is sent after every object is saved. Is there some kind of built in solution for getting my desired notification? If not, how could/should I do it?
There's no built-in notification that gets posted after you've saved a specific batch of objects. Core Data really has no idea how many objects are in your collection, so it has no way to know that you've reached the end of it.
You'll get NSManagedObjectContextDidSaveNotification every time you call save: on the managed object context. You could just wait to save until you've handled all of the objects, which would mean just one NSManagedObjectContextDidSaveNotification.
A better solution is to post your own notification when you know that you've finished the collection. Define a string constant called something like JSONUpdatesCompleteNotification, and post a notification with that name after your last save: call.
NSString *JSONUpdatesCompleteNotification = #"JSONUpdatesCompleteNotification";
Then later, when you know you're done,
[[NSNotificationCenter defaultCenter] postNotificationName:JSONUpdatesCompleteNotification object:self];
Make sure you observe this notification anywhere you need to know about it, and you're done.
Let's assume that I have a program that parses a RSS feed.
I have a method that runs in a thread which keeps checking for updates. If updates is found a NSNotification is created. Is this a stupid implementation?
And is it possible to pass custom parameters within a NSNotification, such as the elementId that was updated.
Sounds like a good plan to me. Yes, you can pass user data.
See NSNotification's notificationWithName:object:userInfo:. The userInfo is an NSDictionary so you can pass whatever you like around.