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

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;

Related

Event notifications in 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

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];
}];

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?

Opening a url on launch

What method must I implement in my cocoa application’s delegate so that on launch, it’ll open a url? (http/https, in this case) I’ve already implemented the url schemes, I just need to know how I can get my application to open on a url notification.
Update: I’m sorry, I wasn’t very clear. My application IS a browser that support https/http urls, but can only open them when it’s already running. What can I do to implement support for open urls in my app on launch?
When an application finishes launching on OS X, NSApp (the global NSApplication instance for the program) sends its delegate the applicationDidFinishLaunching: message (via the notification system). You can implement that method in your delegate to handle the notification and open a browser window in response, using NSWorkspace. Something like the following would work:
// Your NSApp delegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:#"http://www.example.com/"]];
}
It's not a delegate method. You need to implement an Apple Event handler for the getURL event.
As luck would have it, this is exactly the case Apple uses to demonstrate implementing an Apple Event handler.
I already had implemented the getURL event, so that alone isn’t enough to get the application to open a url on launch. The trick is that the AppleEvent must be installed in applicationWillFinishLaunching: not applicationDidFinishLaunching:. Otherwise, the event isn’t sent at all because the app hasn’t registered it in time.
To implement a protocol handler that you can select (in Safari preferences, for example) as the "default browser" and which will launch in response to HTTP / HTTPS, you need to do a few things.
Add .scriptSuite and .scriptTerminology files to your project resources. These will tell Mac OS X that you'll be handling the GetURL command.
Add a CFBundleURLTypes key to your Info.plist file listing the "URL Schemes" that your app will handle.
Also in Info.plist, add the NSAppleScriptEnabled key with the value YES.
Add a new class to your application as a subclass of NSScriptCommand and implement the -(id)performDefaultImplementation selector. From within this function you will find the clicked URL in [self directParameter]. Pass this on to your app's URL handler!
For the full details check out the article:
http://www.xmldatabases.org/WK/blog/1154_Handling_URL_schemes_in_Cocoa.item

Resources