Why isn't application:openFile: called when the application is already running? - macos

I would like to handle open events when a user double-clicks on a file that was created by my application, or drags such a file onto the dock icon.
I've therefore implemented NSApplicationDelegate's application:openFile: and application:openFiles: methods, which work as expected when the application is not running.
However, if the application is already running when the open event occurs, the application becomes focused, but the above methods are never called (breakpoints inside them are not hit) and the files do not open.
I also tried implementing application:openURLs:. This method has the same behaviour: it is not called if the application is already running when the event occurs.
Do I need to implement different functions to handle opening files when the application is already running, or is there something else I need to do/set in order for the existing functions to be called in those circumstances?

This is not mentioned in the documentation, but according to this answer the way that application:openFile: works is that it NSApplication forwards odoc Apple Events to its delegate.
Armed with this knowledge, I was able to find the following old Carbon call in the app:
osError = AEInstallEventHandler(kCoreEventClass,
kAEOpenDocuments,
g_OpenDocumentsUPP,
0L,
false);
I'm presuming this existing event handler consumed the Apple Event before NSApplication had a chance to deal with it. However, when the app is not already running, NSApplication handles the event before the line above setting up the event handler is called, hence the different behaviour.
Removing this old code from the build caused the NSApplicationDelegate methods to be called, thus fixing the issue.

Does the following method work?
- (void)application:(NSApplication *)application
openURLs:(NSArray<NSURL *> *)urls;
If your delegate implements this method, AppKit does not call the
application:openFile: or application:openFiles: methods.

Related

How to use app delegate xcode

how do you call the app delegate methods in the view controller. i want to save my app data before the application terminates. in another app ive created an instance of the delegate and a variable inside it, so every few seconds it checks the delegate if this is true (it sets it to true when the application will resign active) but this doesn't seem the most efficient way to do it.
if you want to save your app data before the application terminates,hen save your data in applicationWillTerminate method of application life cycle.
there is no need to more one delegate, apple already providing you this facility then why you are creating new one. just write your code in applicationWillTerminate method
just reference your viewController from appdelegate & you can call to method in which you want to processing save data.

NSNotificationCenter Observer stops receiving events when app is out of focus on Lion

I have an app that subscribes to a specific kind of notifications from the default NSNotificationCenter.
On OSX Lion, it works fine, except that when the app loses the focus (another app becomes active), it stops receiving the events. When the app gains the focus, it starts receiving events again.
The app did not have this behavior on previous versions of OSX, it always received notifications, even when it was out of focus.
What can I do to change this behavior?
Thanks!
Nathan
I know its a bit late to answer this, still for my records and if some one still searching.
My OS X Menu bar app had the same problem. I wanted the app to observe all states.
Reason:
When the app looses focus,the observer is suspended.
ie. When the application becomes in-active it calls the method
-(void)applicationDidResignActive:(NSNotification *)notification
and by default the NSDistributedNotificationCenter object gets suspended.
Solution:
I created an object for NSDistributedNotificationCenter
NSDistributedNotificationCenter *center=[NSDistributedNotificationCenter defaultCenter];
and then when the app looses focus its call the applicationDidResignActive method and inside
that the NSDistributedNotificationCenter object is made to regain from suspended state by sending NO to setSuspended method.
-(void)applicationDidResignActive:(NSNotification *)notification
{
[center setSuspended:NO];
}
and then app starts observing even when it looses focus.
According to NSDistributionNotificationCenter reference
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDistributedNotificationCenter_Class/Reference/Reference.html#//apple_ref/doc/uid/20000396-BCICEHHB
The NSApplication class automatically suspends distributed notification delivery when the application is not active. Applications based on the Application Kit framework should let AppKit manage the suspension of notification delivery. Foundation-only programs may have occasional need to use this method.
You can either
set the observer's behavior when suspended to NSNotificationSuspensionBehaviorDeliverImmediately using
- (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(NSString *)notificationSender suspensionBehavior:(NSNotificationSuspensionBehavior)suspendedDeliveryBehavior
or set deliverImmediately to YES when posting
- (void)postNotificationName:(NSString *)notificationName object:(NSString *)notificationSender userInfo:(NSDictionary *)userInfo deliverImmediately:(BOOL)deliverImmediately
to send notifications immediately under suspended state.
And make sure you're not periodically killing distnoted.
I forgot I had an old launch agent script to killall distnoted to avoid memory leaks.
It looks like the default behavior when adding an observer to a NSDistributedNotificationsCenter has changed to NSNotificationSuspensionBehaviorCoalesce, that does not deliver notifications when the app is inactive.
Described here:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDistributedNotificationCenter_Class/Reference/Reference.html#//apple_ref/doc/uid/20000396-5567

MACOSX - When calling -finishSyncing on an ISyncSessionDriver the app makes repeated calls to the delegate

I'm using Sync Services in my application. I'm using the normal way of getting the contacts from the address book (using sync services).
I want to prematurely end a sync session if the user decides to do that, therefore, when the user presses the "cancel" button, I make a call to [driver finishSyncing]
Attached to the ISyncSessionDriver is a delegate which deals with delegate methods typical of a sync session. One of those methods is - (BOOL)sessionDriver:(ISyncSessionDriver *)sender willFinishSessionAndReturnError:(NSError **)outError
The problem is that when calling finishSyncing, the sessionDriver:willFinishSessionAndReturnError: gets repeatedly called, not just once, but hunderds of times. Eventually it will throw an error.
So, how could I fix this, or what better debugging can I do to figure out what the problem is?
Thanks
Use instead - (void)cancelSyncing.
Make sure to release the receiver soon afterward because you cannot continue using a canceled session.

How can a Mac app determine the method used to launch it?

I have a Mac OS X application that is also a protocol handler (just as, for example, Safari is a protocol handler for the HTTP and HTTPS protocols). So when a user clicks a link of the form myscheme://some-kind-of-info in any application at all, my application launches to handle the link.
Now I need to be able to determine if the application was launched by such a link click, or if it was launched by any other method. In other words, it was launched by any method besides a link click. (In those cases, I want the app to stay open, but if it was launched by a link it should quit and ignore the link. This way it only operates when already running.)
Is there some way within the app at startup to introspect and find out that it was launched by a standard method rather than by an AppleScript GetURL event? I'd like to find out through a documented method, rather than - for example - just have my app only open these links after it's been running for a half a second.
You can register a handler for each of the possible Apple Events you'll get on launch, and make note of which one you receive first.
If the application is launched without documents, you'll get kAEOpenApplication.
If it's launched with documents, you'll get kAEOpenDocuments (or
kAEPrintDocuments).
If it's launched with a URL, then (obviously) you'll get kAEGetURL.
There's also kAEOpenContents, but I wasn't able to trigger it easily in my test app; it's probably worth supporting no matter what.
How Cocoa Applications Handle Apple Events documents all of this stuff.
There is one error in there, though; it says that AppleScript's "launch" will send kAEOpenApplication. It won't, it'll send ascr/noop (kASAppleScriptSuite/kASLaunchEvent, defined in ASRegistry.h). I couldn't get the usual Cocoa event handler mechanism to trap this event, so you may need to do some more digging there.
One way you can check if the event is sent at launch is to register the event handlers in your application delegate's applicationWillFinishLaunching: method; they should deliver by the time applicationDidFinishLaunching: is invoked. With that method, you could potentially only check for kAEGetURL.

netServiceBrowserDidStopSearch not called

I'm now writing a Bonjour service listener class, according to the document here:
Currently, it seems working, I can receive "netServiceBrowserWillSearch:" and "didFindService:moreComing:" correctly. However, after a long wait, I cannot receive " netServiceBrowserDidStopSearch:" or "netServiceBrowser:didNotSearch:". Therefore I don't know that is the proper time for my delegate class to stop showing some UI.
Could anyone have an idea for this? Thanks.
NSNetServiceBrowser doesn't stop browsing (and call the -netServiceBrowserDidStopSearch: delegate method) until you explicitly tell it to by calling -stop. After it's found the initial services, it continues informing you as new matching services are added or old ones disappear.
How you handle this depends on how you want your app to behave. If you have a window that continuously shows the available services (e.g. like the Bonjour window in iChat), then it's best to let it continue, and contiuously update the list in response to delegate messages. If you've got more like a dialog that gets populated and then goes away once the user makes a selection (e.g like the system Add Printer... dialog), then you want to keep the browser running while it's displayed, then call -stop once the user dismisses it. If you're waiting to find just one specific service, then you can call -stop once you've found and resolved it.

Resources