NSNotification center may not respond to -object? - iphone

I'm trying to make simple use of the NSNotification center inside my iPhone application, but I seem to be doing something wrong in this case. I was under the impression that it was possible to retrieve an object associated with a particular message, or at least a reference to the object, but using the following example code I'm getting a warning,
"NSNotification center may not respond to -object"
- (void)addNewBookmark:(NSNotificationCenter *)notification {
Bookmark *newBookMark = (Bookmark *)[notification object];
//Do some stuff with the bookmark object
}
Indeed, when I compile and run the code, basically nothing I try to do with the contents of the object actually gets carried out - it's simply ignored.
The post code is as follows,
- (IBAction)save:(id) sender{
//Sending the message with the related object
[[NSNotificationCenter defaultCenter]
postNotificationName:#"addNewBookmark"
object:bookmark];
}
and the bookmark object itself is just a dictionary. I also tried using the "userInfo" argument and passing the bookmark object through that, but the result was the same.
How should I be doing this? What am I doing wrong?

Your addNewBookmark: method should accept an NSNotification, not an NSNotificationCenter.
NSNotification should respond to -object as expected.
A notification center is the object in charge of keeping track of who is listening and sending notifications (not centers) to them.

Related

Call a function (IBAction) in a class with a button in another class (and view)

I have an application where I used a UITabBarController with 3 buttons. So I also have 3 classes. What I want to do is to call an - (IBAction) doSomething: (id) sender {} in class 1 (view 1) with a button in class 2 (view 2).
Take whatever it is that your doSomething method (not function) does and use it to create method in a new class. Both controllers can import the class, instantiate it, and use the method.
Alternately you can send a notification to whichever controller has doSomething, but if the code in the method really does apply to both controllers, provide it to both controllers.
You can have one controller send a notification to another. When you want to notify class 1 to perform the button-pressed code you'll send out a notification like this:
[[NSNotificationCenter defaultCenter] postNotificationName:#"ABCPerformButtonAction"
object:nil];
You don't have to call it ABCPerformButtonAction, you just need a string that you'll recognize and something -- I used ABC because I don't know your initials or the name of the app or whatever -- to help ensure you don't accidentally send a notification that has the same name as a notification something you're unaware of is listening for (including 3rd party libraries you're using, etc.).
When that notification goes out, any object that has registered with the defaultCenter to listen for #"ABCPerformButtonAction" will perform any actions you choose. Here's how controller 1 registers (this should be located in some place like ViewDidLoad or the initialization method of the object):
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(performDoSomething:)
name:#"ABCPerformButtonAction"
object:nil];
The selector there, performDoSomething:, is just the name of a method you want to run when the notification goes out. That method has to have a specific format, so you can't call your doSomething method directly. It would look like this:
- (void)performDoSomething:(NSNotification *)notif {
[self doSomething];
}
As you can see, all it does is call the method. Obviously it could do much more, and you can even send information along with the notification (see below).
Lastly, it's important that you also remove your object as an observer before it's deallocated. In your Dealloc method of each object that registered to receive the notification you add this:
[[NSNotificationCenter defaultCenter] removeObserver:self];
Hopefully that makes sense. The Apple documentation for NSNotificationCenter explains more and they provide several sample apps that use notifications.

Reloading view when returning from background

Using iPhone SDK 4.1. Sometimes when returning from the background state on iPhone 3GS device the view returned to has lost one of its images or labels. The viewDidAppear method
doesn't get called either when returning from the background. Is there any way to force
reloading the view so these methods are called?
This usually happens if your app receives a memory warning as a result of trying to store too much data in ram (in this case images).
To test whether this is the case you could either do an NSLog call inside the didReceiveMemoryWarning message or you could subclass UIImage and extend its dealloc and put an NSLog message inside it saying something like "Image being dealloced" and then check what gets written to the console. If you want to check it without being in the debugger (and therefore no console) you could create a debug UILabel inside the mainwindow xib at the very front (so its always visible) whose text value is set instead of writing to NSLog. This way youll be able to see what happened even after you return to your program.
Your best bet is the didReceiveMemoryWarning together with a UILabel object.
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
debugLabel.text=#"Did receive memory warning";
}
To solve the problem (i.e. to reload the images) you could register that view to receive
the UIApplicationWillEnterForegroundNotification from the notification center and then call the necessary reloading calls i.e. check which images are nil (have been released) and should be reloaded.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewNeedsReload) name:UIApplicationWillEnterForegroundNotification object:nil];
- (void) viewNeedsReload
{
//Check validity of each image here and reload if necessary
}

NSNotification in iphone sdk

what is the use of NSNotification in iphone sdk?
Thanks
I know this isn't generally a good way to answer questions, but RTFM.
NSNotification objects encapsulate information so that it can be broadcast to other objects by an NSNotificationCenter object. An NSNotification object (referred to as a notification) contains a name, an object, and an optional dictionary. The name is a tag identifying the notification. The object is any object that the poster of the notification wants to send to observers of that notification (typically, it is the object that posted the notification). The dictionary stores other related objects, if any. NSNotification objects are immutable objects.
You can create a notification object with the class methods notificationWithName:object: or notificationWithName:object:userInfo:. However, you don’t usually create your own notifications directly. The NSNotificationCenter methods postNotificationName:object: and postNotificationName:object:userInfo: allow you to conveniently post a notification without creating it first.
NSNotifications allow you to have a method called when a event occurs.
For example if you have a MPMoviePlayer and you want todo something when it is done you could use the following code:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:yourMoviePlayer.moviePlayer];
or if you want to do something when the device rotates:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:self];
You should have a look at the Notifications section in the Cocoa Fundamentals Guide. There's anything you need to know about notifications there : from definition to use cases.
In terms of events NSNotifications are an alternative to delegation. Delegation can be used to notify one single delegate of an event, whereas notifications can be used to notify an arbitrary number of receivers. A notification is sent to the main notification center, which then notifies every object, that has registered for the notification.
One important difference is, that with delegation you can receive the delegates response to the event, whereas with NSNotifications you just send away the notification, but you don't know about the receivers or their response to the notification.
You register a UINotification when you want to receive a alert from iOS. So if you want to do something when a accessory is plugged in or a TV is plugged in you would register a UINotification for it and it would call a method in your app when the event occurs.

forwarding a notification to another class

I am using this method
- (void)keyboardWillShow:(NSNotification *)notification
that is triggered when the keyboard shows.
When this method is triggered, it receives a notification that contains several parameters about the keyboard, as the animation duration, animation curve and frame. I need to forward this notification and all its parameters to another class. So, I've tried to do this inside keyboardWillShow:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"doSomething" object:notification userInfo:nil];
the doSomething notification runs doSomething method on another class, and it has this form:
- (void) doSomething:(NSNotification *)notification {
but when I try to read the notification values on this other class, using, for example,
myRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
I obtain zero for all values. The notification is losing its parameters and not being forwarded. How can I do that?
thanks.
It is losing all the values because you passed nil when you created the new notification! You must pass the keyboard notification's userInfo dictionary if you want this to work. So:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"doSomething" object:self userInfo:userInfo];
In this case, the object creating this notification is this object. If you want this to appear as to come from the keyboard object, then send [notification object] for object, but I don't recommend this. Also, why not simply have the class that you want to respond to these notifications ALSO listen for keyboard notifications? Creating and sending a new notification from within the keyboard notification call-back seems kind of round-about to me. The other option is to create a delegate-style thing where the class (I am assuming a view controller or something?) actually listening for keyboard notifications then calls back a delegate object (that other class that you want to forward this info to) and passes the userInfo dictionary to it directly. So:
// Assume a proper delegate is set and it responds to - (void)doSomething:(NSDictionary*)userInfo
[delegate doSomething:userInfo]; // from within the keyboard notification
Still, I think I would just have this other class listen for keyboard notifications itself, though.

How to specify notificationSender? (Cocoa Touch)

All of the examples I can find of setting up a notification look like this:
[nc addObserver:self selector:#selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
where object is always being set to nil. object is the notificationSender, which is defined thusly in the documentation:
"The object whose notifications the observer wants to receive; that is, only notifications sent by this sender are delivered to the observer. When nil, the notification center doesn’t use a notification’s sender to decide whether to deliver it to the observer."
I want to receive the keyboard notification only for one particular text view, so I want to tell addObserver that, but I don't know what to give it for the object. I tried the outlet variable that's bound to the text view I'm interested in, but that just resulted in my getting no notifications at all.
Any suggestions?
The UIKeyboardWillShowNotification is coming from your window instance, and for all intents and purposes is a "system" notification. The keyboard is either showing or not showing, it's not really something that is tied to a specific control.
If you want to do something when a user enters a specific text field, you should probably control that in the text field's delegate instead.
In this case you can not get the notification only for one particular text view, as the docu for UIKeyboardWillShowNotification says "The notification object is nil.".
You have to check in your keyboardWillShow impl if your particular text view isFirstResponder.
I had two competing needs - I had to use the keyboard notification because I needed to get the keyboard height, which appears to be only available that way, but I also needed to know which text view I was in, which meant also using the textViewDidBeginEditing delegate. After much messing around I finally resorted to getting the keyboard height in the notification method and storing it in an instance variable, which was then available to use in the delegate method (I need to scroll the view up so the bottom text view is not mostly hidden under they keyboard when they start typing). A bit inelegant, but it works.
Thanks for the pointers!