subclassing NSApplication run
subclassing NSApplication run
- Subject: subclassing NSApplication run
- From: Chinh Nguyen <email@hidden>
- Date: Thu, 18 Dec 2008 13:44:51 -0600
I know everyone is going to say don't do this but I really need to do
this. I need to duplicate the behavior of NSApplication run's event
handling. What the docs say about subclassing run is "This a critical
and complex task, however, that you should only attempt with good
reason." with no further information. I've got a good reason and I
can get into more detail about why later if necessary.
My app is a cross platform app (Mac, Windows, and Unix) that all run
in a single thread and share the same event handling model--the app
controls the event loop. The app has an "engine" that controls
everything such as processing commands, creating graphs, running
scripts, displaying help files, etc. 90% of the app's functionality
must run through the engine which are submitted as commands. Although
most of the engine is not reentrant, it makes sure it's in a safe
state when it polls in case the GUI needs to, for example, create and
display a programmable dialog from a script on disk that describes the
dialog while it's already creating a complicated graph.
It's not practical to rewrite this behavior in the app although we're
taking steps towards instancing up the engine. However, it'll be
quite some time before that happens and our users are clamoring for
the 64-bit version of our app now (necessary for the huge amount of
data they work with).
I've been working on porting my Carbon app to Cocoa for 64-bit
support. Because NSApplicationMain() (and namely, NSApplication run)
never returns, I created a separate worker thread for the engine to
run in (the old polling logic is macro'd to nothing). It's constantly
looping waiting for commands to be submitted to it (it does idle when
necessary though). This works great but the problem is that the
engine is not thread-safe. Since neither is AppKit, I'm constantly
having to make sure methods perform in the right thread otherwise I
get crashes. I'm still going through my code to do this and it's
really tedious. This biggest issue is that I've found the GUI to be
quite sluggish in some instances. For example, the GUI may respond to
an event by performing code in the worker thread (without waiting, a
must) which may in turn may perform GUI methods in the main thread
(while waiting). Not waiting for methods to perform in the main
thread speeds things up a little but I haven't confirmed whether
that's safe yet.
So I've decided to investigate going back to the original single-
threaded polling model. To avoid being blocked by NSApplication run,
I duplicated the behavior of NSApplicationMain() and part of run by
initializing my NSApplication instance, loading my main nib, then
invoking finishLaunching. Control then goes to my engine as before.
I poll using nextEventMatchingMask:untilDate:inMode:dequeue: and
sendEvent:. I just added this earlier today and my app seems to be
running OK, is much snappier in the situations where it was sluggish
in the multi-threaded model, and I haven't observed any memory leaks.
However, I noticed that after a closing a window, the previous key
window does not become key. I can add code to handle this but I'm
concerned there are other things going on in NSApplication's run
method do/while loop that I'm missing. Can anyone tell me what else I
need to do in my event loop?
Again, I can get into more detail about why my app has to behave the
way it does for clarification.
-Chinh Nguyen
email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden