Cannot get Cocoa notifications to work - objective-c

Settting up the observer code:
NSNotificationCenter *defaultCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
[defaultCenter addObserver:self
selector:#selector(updateLog:)
name:#"Update Log"
object:nil];
Sending the notification code:
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update Log" object:self];
With the method defined as:
-(void)updateLog: (NSNotification *) notification {
NSLog(#"Update Log"); }
The text "Update Log" does not appear in the log when the notification is sent.
Thanks for any ideas for why this code is not working.

There is a difference between "the notification center for workspace notifications" Apple:
[[NSWorkspace sharedWorkspace] notificationCenter]
and "the process’s default notification center" Apple:
[NSNotificationCenter defaultCenter]
You need to pick one of those to use.

Related

Objective-C: How to remove notification by selector?

When setting up notification, you can set different selector to react to it. But there seems no way to remove notification by selector. For example:
// e.g. React to background notification by calling method 1
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(method1:) name:notification object:nil];
// e.g. React to background notification by calling method 2
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(method2:) name:notification object:nil];
Now when the notification fires, both methods will react to it.
How do I remove notification selectively (e.g. remove notification handler method1)?
There is a way to do it, but I don't think you will like it.
Use -addObserverForName:object:queue:usingBlock: instead.
__weak typeof(self) weakSelf = self;
// e.g. React to background notification by calling method 1
self.method1Observer = [[NSNotificationCenter defaultCenter] addObserverForName:notification object:nil queue:nil usingBlock:^(NSNotification *note) {
[weakSelf method1:note];
}];
// e.g. React to background notification by calling method 2
self.method2Observer = [[NSNotificationCenter defaultCenter] addObserverForName:notification object:nil queue:nil usingBlock:^(NSNotification *note) {
[weakSelf method2:note];
}];
Then later on:
// Remove method 1 observer while keeping method 2 observer.
if (self.method1Observer != nil) {
[[NSNotificationCenter defaultCenter] removeObserver:self.method1Observer];
self.method1Observer = nil;
}
Update: I forgot to nil check self.method1Observer before passing it to -removeObserver:.
you have to remove that notification when it will not necessary in that class. So simply use below code for remove already added Notification.
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"Notification" object:nil];

Subscribe (or list) all of an applications distributed notifications

I need a list of all the distributed notifications that iTunes and Spotify publish. I can't seem to find such a thing on SO or Google, so I wanted to see if maybe I could just subscribe to all the notifications and just note down which ones are triggered. I've successfully subscribed to one, but I can't subscribe to all of them.
// Works just fine
NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(itunesNotification)
name:#"com.apple.iTunes.playerInfo" object:nil];
[center addObserver:self selector:#selector(spotifyNotification)
name:#"com.spotify.client.PlaybackStateChanged" object:nil];
// Doesn't work :(
[center addObserver:self selector:#selector(itunesNotification)
name:#"com.apple.iTunes" object:nil];
[center addObserver:self selector:#selector(itunesNotification)
name:#"com.apple.iTunes.*" object:nil];
// Same result with com.spotify.client and .*
Again, if I could have a list of all the iTunes/Spotify notifcations, that would work as well. My intention is not to subscribe to all notifications in the end, but rather to see what's out there and pick a few. Hope that makes sense, thanks a bunch!
I figured it out! You can observe all of the distributed notifications on your Mac by supplying nil as the name.
NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(allNotifications:) name:nil object:nil];

Handle device rotation for "More" UINavigationController in UITabBarController.moreNavigationController

I have an app which has to work in both portrait and landscape more and the UITabBar should adjust to current orientation (it has custom background and selected items). So, for the rest of views I just override the - (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation method and it works perfectly.
How would I do that for the .moreNavigationController of UITabBarController ? I've tried adding an observer (the selector is in extension of UITabBarController):
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:self.moreNavigationController];
but it never get called.
Am I missing something or what would be the best way to handle this situation ?
Solution: somewhy UIDeviceOrientation is not firing correctly, so better to use statusBarOrientation, works as a charm.
the final code which work is this:
in main UITabBarController, viewDidLoad:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
the didRotate selector method:
- (void) didRotate:(NSNotification *)notification{
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if(UIInterfaceOrientationIsPortrait(orientation)) {
// Portrait
} else {
// Landscape
}
}
Thanks for help.
You are registering your UITabBarController for a notification which never gets posted. Take a look at the documentation NSNotificationCenter Reference for the addObserver:selector:name:object method
- (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender
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.
so, if you specify the . moreNavigationController as the sender, you wont get those notifications, because it never posts such ones. Instead pass nil to ignore the sender and listen to the status bar change regardless of who sent it.
By the way, in this SO Answer is a summary of how you can react to orientation change.
And at last. If it still doesn't work, you can try this:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
Yes, you forgot to post notification, which will call you own notification:
[[NSNotificationCenter defaultCenter] postNotificationName: UIApplicationDidChangeStatusBarOrientationNotification object:self];
or if you dont wont to send anything just set object as nil:
[[NSNotificationCenter defaultCenter] postNotificationName: UIApplicationDidChangeStatusBarOrientationNotification object:nil];
The best way to implement the same is first addObserver and then remove observer to avoid the crash:-
-(void)viewDidLoad{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
//Now Remove Observer
-(void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self #"UIDeviceOrientationDidChangeNotification" object:nil];
}

Use NSWorkspaceDidWakeNotification to activate method?

I created a simple app to learn how to use NSWorkspaceWillSleepNotification and NSWorkspaceDidWakeNotification. My goal is to call a method when the computer sleeps and wakes. The app I created will change each label accordingly. After building the app, I launch it from my desktop. After the application is launched, I put the computer to sleep. When the computer wakes the labels in the application do not change. I added IBAction buttons to the window to make sure that the labels would change. When buttons are pressed the labels do indeed change. But I want something like this to happen automatically upon sleep and wake. What am I doing wrong?
#import "Controller.h"
#implementation Controller
- (void)fileNotifications {
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
selector: #selector(makeSleep:)
name: NSWorkspaceWillSleepNotification
object: nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
selector: #selector(makeWake:)
name: NSWorkspaceDidWakeNotification
object: nil];
}
- (IBAction)makeSleep:(id)sender {
[sleepLabel setStringValue:#"Computer Slept!"];
}
- (IBAction)makeWake:(id)sender {
[wakeLabel setStringValue:#"Computer Woke!"];
}
#end
Instead of [[NSWorkspace sharedWorkspace] notificationCenter] try using [NSNotificationCenter defaultCenter]
like this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(makeSleep:)
NSWorkspaceWillSleepNotification
object:nil
];
and
[[NSNotificationCenter defaultCenter] addObserver:self
#selector(makeWake:)
NSWorkspaceDidWakeNotification
object:nil
];
The above is incorrect, see https://developer.apple.com/library/mac/qa/qa1340/_index.html
Using [[NSWorkspace sharedWorkspace] notificationCenter] is necessary.
You should add observers upon - (void)awakeFromNib method.

Cocoa Custom Notification Example

Can someone please show me an example of a Cocoa Obj-C object, with a custom notification, how to fire it, subscribe to it, and handle it?
#implementation MyObject
// Posts a MyNotification message whenever called
- (void)notify {
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:self];
}
// Prints a message whenever a MyNotification is received
- (void)handleNotification:(NSNotification*)note {
NSLog(#"Got notified: %#", note);
}
#end
// somewhere else
MyObject *object = [[MyObject alloc] init];
// receive MyNotification events from any object
[[NSNotificationCenter defaultCenter] addObserver:object selector:#selector(handleNotification:) name:#"MyNotification" object:nil];
// create a notification
[object notify];
For more information, see the documentation for NSNotificationCenter.
Step 1:
//register to listen for event
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(eventHandler:)
name:#"eventType"
object:nil ];
//event handler when event occurs
-(void)eventHandler: (NSNotification *) notification
{
NSLog(#"event triggered");
}
Step 2:
//trigger event
[[NSNotificationCenter defaultCenter]
postNotificationName:#"eventType"
object:nil ];
Make sure to unregister notification (observer) when your object is deallocated. Apple documentation states: "Before an object that is observing notifications is deallocated, it must tell the notification center to stop sending it notifications".
For Local Notifications the next code is applicable:
[[NSNotificationCenter defaultCenter] removeObserver:self];
And for observers of distributed notifications:
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];