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

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.

Related

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

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.

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.

NSDocumentController not quitting app properly on review unsaved documents in Cocoa/Objective-C

I've been banging my head on walls trying to solve this.
My app uses a subclass of NSDocument, NSDocumentController and also NSWindowController. The issue is that when I create a document and make a modification, and also if I create more than one document the same way, if I choose Quit while documents are unsaved, I get the proper dialogs to ask wether I want to Review unsaved docs, Cancel or Not save, but whenever I select to Review and then save a document, I get to save, but after saving the first document, first, that document is NOT closed, and I am not asked to save the others. On top of this, My App's Quit menu item becomes grayed out.
I created another skeleton app to do the same thing, and of course, all works normally. I checked my connections in the nib file, and cannot see anything wrong, or different from the test app. Although there is a lot more in my app.
I am not currently overriding the reviewUnsavedDocumentsWithAlertTitle:cancellable:delegate:didReviewAllSelector:contextInfo: method, but when I do, I get the same problem, since I call Super's version of it after doing some special clean-up work. But again, not overriding this yields the same result.
One thing I do notice, is that in my own App, I get the following messages in the Log as I run it, which I do not get in my test app:
[Switching to process 9997 thread 0x7667]
[Switching to process 9997 thread 0x903]
Which makes it look like I am doing something multi-threaded here without knowing. My test app doesn't switch to another thread.
I'm not sure how to check if all my connexions are ok and why these threads are being switched to and where they come from.
Since I get the error wether or not I override the NSDocumentController methods like the one above or the closeAllDocumentsWithDelegate:didCloseAllSelector:contextInfo: I imagine the error comes from somewhere else.
Maybe my NSDocument subclass's saving methods are creating the issue, but they return the appropriate values once the save has occurred, I get no error and the files are all fine.
I'd like to override the -didCloseAllSelector or -didReviewAllSelector, but I'm a bit challenged with this. I'm not sure how to build the method, since this:
- (void)documentController:(NSDocumentController *)controller
didCloseAll:(BOOL)didCloseAll contextInfo:(void *)contextInfo;
{
NSLog(#"All documents closed");
}
is never called. Is this a symptom? Tried the same for the -didReviewAllSelecter which never gets called.
Finally, I was overriding a method in my "NSDocument" subclass which I should not have. Removing this fixed it.
I guess you have to be really careful what you override!
The method was writeToFile:ofType:originalFile:saveOperation: which I no longer had to do.
Not sure exactly what was wrong, but it may help others to know to look there.

Force NSBrowser to reload

I'm new to Cocoa so apologies if this doesn't make sense.
I'm using an NSBrowser to get a Finder-style column view of some data from a web service.
The NSURLConnection result is returned asynchronously.
My issue is that the browser correctly calls its delegate to populate columns when the app starts, but I can't make it reload once I've got the data.
I've tried reloadDataForRowIndexes, noteHeightOfRowsWithIndexesChanged, addColumn, reloadColumn and loadColumnZero, but none of them trigger the browser to call numberOfRowsInColumn on the delegate as I would expect (and see on startup).
I know the browser delegate is ok because I can see it being called at startup.
Is there another way to ask the browser to refresh, or do I need to try another approach?
Plan B would be to fire the urlConnection off on another thread, and block the browser. I'm not keen on blocking the UI thread as I fear this will cause a beachball.
Plan C maybe would be to delay the browser loading from the nib file until the data was ready, but I'd have a similar issue next node unless I load all nodes a column early in anticipation.
[browser reloadColumn:0] did not work for me but [browser loadColumnZero].
[browser reloadColumn:0] is the right way to go. This just works, no workaround needed. Your error is elsewhere if this does not work for you.

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