Event notifications in macOS - macos

Is it possible for a macOS application to listen for specific events originating from another application?
I'd like to detect when Time Machine backups are initiated, in order to create point-in-time snapshots of the NAS folder where the sparsebundle is located.

The Time Machine engine sends distributed notifications.
Add an observer
Objective-C
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleNotifications:)
name:nil
object:nil];
Swift
DistributedNotificationCenter.default().addObserver(self, selector: #selector(handleNotifications), name: nil, object: nil)
and implement the corresponding selector
Objective-C
- (void)handleNotifications:(NSNotification *)notification {
NSLog(#"%#", notification);
}
Swift
#objc func handleNotifications(_ notification : Notification) {
print(notification)
}
You have to filter the notifications related to Time Machine. You can also observe specific notifications via the name parameter

Related

Is there an onSave hook for Parse local datastore (on iOS)?

While Parse Cloud Code provides an on-save hook that lets you perform custom actions on the backend when objects are saved, their iOS SDK doesn't have any similar hook for when objects are saved into the local datastore with -save(Eventually)* methods.
I would like changes in data to drive my custom actions, such as update the application's UI, refreshing a table etc.. How could this be done? Are there any NSNotifications that you could observe?
A lot would depend on if your local "afterSave" is dependent on confirmation of a save in the cloud or not. Consider the following two examples.
You can pinInBackgroundWithBlock and send a notification as well as save eventually. The notification would send right away unless there was an error pinning. Keep in mind that your saveEventually could still fail.
[myObject pinInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if( succeeded ){
[[NSNotificationCenter defaultCenter]postNotificationName:#"localBeforeSave" object:myObject];
[myObject saveEventually];
}
}];
Or you can just use a block to send a local notification once you can confirm that the save eventually completed.
[myObject saveEventually:^(BOOL succeeded, NSError *error) {
[[NSNotificationCenter defaultCenter]postNotificationName:#"localAfterSave" object:myObject];
}];

How to prevent setting of [NSApp dockTile] badgeLabel value that is set not by my code?

I have a push notifications with badge, sounds and alerts enabled.
If the program is not running - everything is fine. But when the program is running - I need to block all sounds, alerts and badges that are not generated by program, because I have a live connection to my server and receiving all events before APNS sends notifications to my mac device.
I've found the way to hide alerts, but I couldn't find any way to take over control on dockTile's icon badge.
if i do this:
-(void)application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[[NSApp dockTile] setBadgeLabel:nil];
}
nothing is happened, the badge that is set by APNS still persists. I tried to KVO on badgeLabel or dockTileNumber property as shown here, but observeValueForKeyPath:ofObject:change:context: is never called. How do APNS sets the badgeLabel? Maybe I am doing something wrong and there is a correct way to disable alerts/sounds/badges when the program is running?
Since i did not found any solutions to do it correctly, i will accept my workaround:
-(void)application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[application dockTile].badgeLabel = #" ";
[application dockTile].badgeLabel = #"";
}
Alerts may be disabled via NSUserNotificationCenterDelegate delegate method userNotificationCenter:shouldPresentNotification::
-(BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
{
//apple push notification alert will contain userInfo with aps payload, so disable here
if (notification.userInfo[#"aps"])
return NO;
return YES;
}
I haven't found any ways to disable sounds.

How to send event or message to external process in Mac?

In Windows I can post custom message to another process and inform it to do an action like:
PostMessage(WindowOfAnyProcess, WM_CUSTOM_MESSAGE, param1, param2)
What is the alternative on Mac OS? Does Carbon Events help me? How?
Thankyou.
Assuming that both of the processes are yours, you can use NSDistributedNotificationCenter to send notifications and data to each process.
To do this do something like:
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:#"HelloFromProcessOne" object:nil]
If you want to include data you can use:
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:#"HelloFromProcessOne" object:nil userInfo:[NSDictionary dictionaryWithObject:#"some info here" forKey:#"data"]]
A note should be added that:
Sandboxed apps can send notifications only if they do not contain a dictionary. If the sending application is in an App Sandbox, notificationInfo must be nil. This means that you won't be able to provide information with the notification if you intend on targeting the Mac AppStore.
To make the application receive the notifications do something like:
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:#selector(someNotificationUpdate:) name:#"HelloFromProcessOne" object:nil]
someNotificationUpdate: would be declared like:
- (void)someNotificationUpdate:(NSNotification *)note;

Never getting iCloud change notifications

I am working on Core Data syncing over iCloud between two Mac applications. I have it mostly working (based on http://timroadley.com/2012/04/03/core-data-in-icloud/) - data is being synced, but I'm never getting the content change notification I need to merge the changes into my local context.
In my AppDelegate's managedObjectContext method:
NSManagedObjectContext * moc = [[NSManagedObjectContext alloc]
initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc performBlockAndWait:
^{
[moc setPersistentStoreCoordinator:coordinator];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mergeChangesFrom_iCloud:)
name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:coordinator];
}];
My observer function never gets called:
- (void) mergeChangesFrom_iCloud:(NSNotification*) notification
{
NSLog(#"Merging changes from iCloud");
// everything past here is irrelevent - this log message never appears
The data store is most certainly being synced - deleting a record in app A and forcing a table reload in app B results in a Core Data fault failure as expected for unmerged changes. Quitting and restarting app B shows the correctly updated data.
A breakpoint on the addObserver call shows it is being called. A breakpoint in mergeChangesFrom_iCloud shows that it is not.
Why is the coordinator apparently never sending the NSPersistentStoreDidImportUbiquitousContentChangesNotification as the documentation (and tutorials) claim it should? Where can I begin debugging this?
Update
The mystery deepens. Using the Core Foundation function shown here - NSNotificationCenter trapping and tracing all NSNotifications - I do not see NSPersistentStoreDidImportUbiquitousContentChangesNotification appear at all among the mass of notifications flying by.
It looks like it's not being posted at all - nor do I see any other Core Data related notifications after the initial load happens on startup.

NSUserDefaultsDidChangeNotification not firing when it should… or at all?

In my application, I have registered the NSUserDefaultsDidChangeNotification notification in awakeFromNib along with my other notifications (which are working fine). I register it just as shown below, which appears to be correct:
- (void)awakeFromNib
{
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:#selector(myAction:) name:NSUserDefaultsDidChangeNotification object:nil];
}
and my action method appears to be correctly formatted as well:
- (void)myAction:(NSNotifcation*)notifcation
{
NSLog(#"foo);
}
For unknown reasons, however, it refuses to fire at all. No matter how many of the application's defaults are changed, it never fires even once. Am I registering wrong or is something else the cause? Has anybody else experienced this problem in the past?
Have you tried using [NSNotificationCenter defaultCenter] instead of the workspace notification center?

Resources