Notifications and sending object values - beginners help please - objective-c

Ive set up a notification centre with the following code in a class called ConnectionController
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(aChangeCalendarMethod:) name:#"updateCalendar" object:nil];
And have a sender in another class (MonthFieldValidator)
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateCalendar" object:self];
MonthFieldValidator has a property of NSString type called month which I want to pass the value of back to connection controller.
All I seem to be able to do is get this
Printing description of testObject:
(NSObject *) testObject = 0x4055c00000000000
And the object doesn't have the month property (or at least that I can access).
Presumably I will have to useruser info?

Do this:
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateCalendar" object:yourMonthStringHere];
Method that will be called is:
-(void)aChangeCalendarMethod:(NSNotification*)notification
{
NSString *strMonth = (NSString *)[notification object]; //retrieve passed string like this
//continue other code
}

Related

OCMock notification observer - verifying the object

I've recently started working with OCMock framework and trying to figure out how to use the notification observer. So in my source code I'm observing some notification:
typedef enum {
OperationStatusCompleted,
// Some other statuses
} SomeOperationStatus;
- (void)addObserverForSomeNotification {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(someOperationStatusDidChange:)
name:#"someOperationStatusDidChange"
object:nil];
- (void)backgroundOperationStatusDidChange:(NSNotification *)notification {
id<SomeOperationProtocol> operation = [notification object];
if (operation.status == OperationStatusCompleted) {
// Do something.
}
}
Now I want to add the expectation for that notification in my test:
- (void)testNotification {
id observerMock = OCMObserverMock();
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:#"someOperationStatusChanged" object:nil];
[[observerMock expect] notificationWithName:#"someOperationStatusChanged" object:[OCMArg any]];
// run the test ...
}
That by itself works fine and I'm receiving the notification in the test but what I actually want to check is the status of the object of the notification (meaning that I've received a notification with specific object with specific status). Is it possible?
I finally figured out how to do it:
[[observerMock expect] notificationWithName:#"someOperationStatusChanged" object:[OCMArg checkWithBlock:^BOOL(id<IMBBackgroundOperation> param) {
return param.status == OperationStatusCompleted;
}]];

How to send a string along with NSNotification?

I'm trying to write a plugin for phonegap/cordova that allows audio to resume when interrupted by a phone call. I'm using AVAudioSesionInterruptionNotification and it is working well. However, I need to be able to send a string to my event handler, but I can't figure out how.
I'm setting up an event listener here and calling it from the javascript layer:
- (void) startListeningForAudioSessionEvent:(CDVInvokedUrlCommand*)command{
NSString* myImportantString = [command.arguments objectAtIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onAudioSessionEvent:) name:AVAudioSessionInterruptionNotification object:nil];
}
and I'm handling the event here:
- (void) onAudioSessionEvent:(NSNotification *)notification
{
if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){
//do stuff using myImportantString
}
}
can't figure out how to pass myImportantString over to onAudioSessionEvent. I know very little Objective-C (hence my use of cordova), so please respond as if you're talking to a child. Thanks!
By the way, I'm simply trying to add a couple of methods on top of cordova's media plugin found here: https://github.com/apache/cordova-plugin-media/tree/master/src/ios
so the code above is the entirety of my .m file minus this part
#implementation CDVSound (extendedCDVSound)
It's probably easier to use the block-based API for adding an observer:
- (void) startListeningForAudioSessionEvent:(CDVInvokedUrlCommand*)command{
NSString* myImportantString = [command.arguments objectAtIndex:0];
id observer = [[NSNotificationCenter defaultCenter] addObserverForName:AVAudioSessionInterruptionNotification
object:nil
queue:nil
usingBlock:^(NSNotification *notification){
if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){
//do stuff using myImportantString; you could even skip the use of that
//temporary variable and directly use [command.arguments objectAtIndex:0],
//assuming that command and command.arguments are immutable so that you
//can rely on them still being the same
}
}];
}
By using the block-based API, you can directly reference any variables that are in scope at the time the observer is added in the code which is invoked when the notification is posted.
When you're done observing, you need to remove observer as an observer of the notification.
Like this:
// near the top of MyController.m (above #implementation)
#interface MyController ()
#property NSString *myImportantString;
#end
// inside the implementation
- (void) startListeningForAudioSessionEvent:(CDVInvokedUrlCommand*)command{
self.myImportantString = [command.arguments objectAtIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onAudioSessionEvent:) name:AVAudioSessionInterruptionNotification object:nil];
}
- (void) onAudioSessionEvent:(NSNotification *)notification
{
if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){
//do stuff using self.myImportantString
}
}

Why doesn't the block gets called with NSNotificationCenter?

I just came across the NSNotificationCenter method [NSNotificationCenter defaultCenter] addObserverForName: object: queue: usingBlock: method and since I'm beginning to be comfortable using blocks I decided to try it out since I results in better code readability.
But for some reason I can't get it to work. For what reason doesn't this work
[[NSNotificationCenter defaultCenter] addObserverForName:#"SomeNotificationName"
object:self
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(#"This doesn't work");
// ... want to do awesome stuff here...
}];
where as this works just fine
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(aMethod)
name:#"SomeNotificationName"
object:nil];
//...
//....
- (void)aMethod {
NSLog(#"This works");
// ... doing awesome stuff here...
}
END NOTE
Thanks, for future reference this is my final solution
// declared instance variable id _myObserver;
//...
_myObserver = [[NSNotificationCenter defaultCenter] addObserverForName:#"SomeNotificationName"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(#"It's working! It's working!!");
// ... again doing awesome stuff here...
}];
And then finally, (when I'm done with the object)
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:_myObserver];
}
Read the doc more carefully :) In the block version, you have to store the return "token" object, for instance in an ivar.
id obj = [[NSNotificationCenter defaultCenter]
addObserverForName:#"SomeNotificationName"
object:self
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(#"This doesn't work");
// ... want to do awesome stuff here...
}];
//you need to retain obj somehow (e.g. using ivar)
//otherwise it will get released on its own under ARC
Also (as mentioned in the docs too), don't forget to remove the observer when you're done with it. In my case, this usually happens in the dealloc method of my window/view controller. In your case it may be at a different place. (Of course, if you want the observer until your app quits, you don't need to do this.)
- (void)dealloc {
//assuming you stored it in _obj ivar
[[NSNotificationCenter defaultCenter] removeObserver:_obj];
//no super dealloc under ARC
}
The object parameter in both methods is the sender of the notification.
In the block based one you are passing self, in the selector based one you are passing nil. That means the block based observer will listen only to notifications generated by self.

Giving notification to another class with NSNotificationCenter

So my goal is to deliver a notification to another class with using NSNotificationCenter, I also want to pass object with the notification to the other class, how should I do this?
You must first register a notification name
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(startLocating:) name:#"ForceUpdateLocation" object:nil]; // don't forget the ":"
And then post a notification with a dictionary of parameters
[[NSNotificationCenter defaultCenter] postNotificationName:#"ForceUpdateLocation" object:self userInfo:[NSDictionary dictionaryWithObject:#"1,2,3,4,5" forKey:#"categories_ids"]];
and the method will be
- (void)startLocating:(NSNotification *)notification {
NSDictionary *dict = [notification userInfo];
}
Just call any method for posting notifications as described here, for instance :
to post a notification :
-(void)postNotificationName:(NSString *)notificationName
object:(id)notificationSender
userInfo:(NSDictionary *)userInfo;
where userInfo is a dictionary containing useful objects.
On the other side to register for notifications :
-(void)addObserver:(id)notificationObserver
selector:(SEL)notificationSelector
name:(NSString *)notificationName
object:(id)notificationSender;
You could also check Apple's Notification Programming Topics.

Objective-C Mac OS X Distributed notifications iTunes

i need a little help, i currently have a method; updateTrackInfo in my Mac OS X application which gets the artist name, the track name and duration of the track currently being played in iTunes
However i want the app to listen for the distributed iTunes notification; com.apple.iTunes.playerInfo then call the method updateTrackInfo when ever the notification is distributed by iTunes. Please could someone help me, on what i would need to write in both the header and implementation file.
Thanks, Sami.
You're looking for -[NSDistributedNotificationCenter addObserver:selector:name:object:]:
NSDistributedNotificationCenter *dnc = [NSDistributedNotificationCenter defaultCenter];
[dnc addObserver:self selector:#selector(updateTrackInfo:) name:#"com.apple.iTunes.playerInfo" object:nil];
Elsewhere in the same class...
- (void) updateTrackInfo:(NSNotification *)notification {
NSDictionary *information = [notification userInfo];
NSLog(#"track information: %#", information);
}
It even gives you a whole bunch of track information in the notification. Isn't that nice?
Thanks for your help, you helped me correct my code, I had this written up:
- (id) init {
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"com.apple.iTunes.playerInfo"
object:nil];
return self;}
- (void) receiveNotification:(NSNotification *) notification {
if ([#"com.apple.iTunes.playerInfo" isEqualToString:#"com.apple.iTunes.playerInfo"]) {
NSLog (#"Successfully received the test notification!");
}}
But it used NSNotificationCenter instead of NSDistributedNotificationCenter. Which is where I was going wrong.
Thanks, Sami.