Re: NSApplication terminate: behavior
Re: NSApplication terminate: behavior
- Subject: Re: NSApplication terminate: behavior
- From: Camillo Lugaresi <email@hidden>
- Date: Sat, 21 Jan 2006 00:01:33 +0100
On 20/gen/06, at 23:23, Andreas Färber wrote:
Am 20.01.2006 um 22:15 schrieb Camillo Lugaresi:
I did try calling stop: from applicationShouldTerminate:
returning NS***Cancel and, like I said in the above quote, it
worked in taking me back to my Main method. However I did not
find an easy way to terminate (as opposed to "terminate:") the
Cocoa NSApplication, leaving the windows, application menu etc.
on screen until after my main application was already exited.
I think stop just sets a flag that tells run to stop looping; if
you call it in applicationShouldTerminate, you're already inside
terminate and exit is going to be called anyway. You need to
prevent terminate from being called,
a) If in ***shouldTerminate I return ***Cancel
(NSApplicationTerminateReplyCancel?) it does not terminate;
b ) if I return *Now it terminates immediately, not returning to
Main as usual, and
c) if I return *Later the main loop is halted, not returning to Main.
If I call stop: before I return Cancel, I get out of the run loop
and back to Main but the application is still alive, just no
runloop active.
Ah, righ it makes sense that calling stop and then cancelling the
termination attempt gets you out of the run loop. I must have misread
you before.
Are you saying that you already implemented everything the
documentation says (calling app delegate methods, document-based
app methods, sending the notification, all in the right order),
and things still aren't getting cleaned up correctly?
There's also the possibility that it's not a Cocoa problem at all.
For example, AppKit might not be destroying windows when the app
quit, instead relying on a lower layer mechanism (such as an
atexit callback that tells the window server that the app is going
down, so it can destroy all of its windows?).
However, the important application-specific cleanup is done inside
delegate methods. As long as you're calling them as stated in the
documentation, documents will be closed, preferences will be
saved, etc.
Could you please explain this further? What delegates exactly are
you referring to? The AppKit NSApplication documentation says this
about terminate:
<<This method is typically invoked when the user chooses Quit or
Exit from the application’s menu. Each use of terminate: invokes
applicationShouldTerminate: (page 144) to notify the delegate that
the application will terminate. If applicationShouldTerminate:
(page 144) returns NO, control is returned to the main event loop,
and the application isn’t terminated. Otherwise, the document
controller of the application (if one exists) is asked to check its
documents and, if there are unsaved changes, ask the user to save
those changes. Then, this method posts an
NSApplicationWillTerminateNotification (page 147) to the default
notification center. Don’t put final cleanup code in your
application’s main() function—it will never be executed. If cleanup
is necessary, have the delegate respond to
applicationWillTerminate: (page 145) and performcleanup in that
method. >>
The YES or NO is actually replaced by the three enum values
referenced somewhere above, as specified in the delegates'
documentation.
Now are these the two delegates that you say I should call myself?
Don't they just enable *me* to react to these events?
Yes, although I think there might be other parts of Cocoa that depend
on the NSApplicationWillTerminateNotification. I was under the
impression that you were trying to load an existing Cocoa
application, in which case ensuring that delegate methods are called
as specified in the docs is crucial.
And how exactly would I invoke them anyway?
For example,
delegate = [NSApp delegate];
if (delegate) reply = [delegate applicationShouldTerminate:NSApp];
...etc. Use NSNotificationCenter to send the
NSApplicationWillTerminateNotification.
You should probably also go throught the window list and close each
window, eg:
NSArray *windows = [NSApp windows];
unsigned count = [windows count];
while (count--) {
[[windows objectAtIndex:count] close];
}
Finally, I guess you can try calling [NSApp release];
Right now when experimenting with stop: I do not know what exactly
to do from there! That's one of the questions. The documentation
does not say "call this, do that", the above quote and other places
just describe that terminate: is calling the two mentioned
delegates, but does not say anything else it might be doing.
Yes, I don't see the details are documented anywhere. However, since
you have full control of the application, you have the advantage that
you don't have to worry about all possible side-effects that might
not happen, but only the ones which are important to you.
And to make it very clear I do not want to call anything from my
Main method that again would result in a call to exit() on the side
of Cocoa. Just close and release the windows, views, controls, menu
and let me return to my NSAutoreleasePool wrapper and other managed
non-Cocoa objects.
The things I outlined above should be a start. Once you have
implemented them, see what's missing.
Unfortunately, I think it will have to be a process of trial and
error unless someone who knows Cocoa's internals decides to shed some
more light on the termination process.
You could also consider stopping the application right before
terminate is called, then setting a breakpoint on objc_msgsend (and
the other versions of that call) that logs each method call and then
continues. That should give you a log of the methods called during
terminate, which might be useful.
Camillo _______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden