Re: Writing application without Interface Builder
Re: Writing application without Interface Builder
- Subject: Re: Writing application without Interface Builder
- From: Patrick Hartling <email@hidden>
- Date: Sat, 22 Jul 2006 08:21:11 -0500
Bill Bumgarner wrote:
> ... lots of conjecture about threading, appkit, & the main menu deleted ...
I apologize for being vague about the threading and all of that. I will post
some code this time, though I hope not to make this message overly long as a
result.
> OK -- it is pretty clear from your post that you don't have an full
> understanding of the interaction between the AppKit, Threads, and the
> Main Menu.
I'm sure that you are right. I am new to Cocoa programming, and it seems
like what I want to do is not what people normally try to do with Cocoa--and
not just because I started out by trying to write a lot of the code by hand.
I have since used Interface Builder to set up the main menu, and it
generally works much better than what I was doing by hand.
[snip]
> Threading and the AppKit:
>
> The AppKit needs a running run loop to function. That runloop needs to
> be running in the main thread -- the initial thread that was used to
> start the app. While a growing chunk of the AppKit is threadsafe, it
> is -- by and large -- not thread safe. The documentation will
> explicitly call out what is thread safe.
I have one run loop in the primordial thread and one in each of the threads
that I create using NSThread.
> If you cannot find something that explicitly states a piece of API is
> thread safe, then *** it is not thread safe ***. Period. End of
> story. No amount of thread locking around said API will make it thread
> safe.
OK.
> NSApplicationMain()
>
> Though a rather odd spot for it, NSApplication's class documentation
> indicates that NSApplicationMain() is effectively implemented as follows:
>
> void NSApplicationMain(int argc, char *argv[]) {
> [NSApplication sharedApplication];
> [NSBundle loadNibNamed:@"myMain" owner:NSApp];
> [NSApp run];
> }
[snip]
Right, I have adapted this basic example for my purposes. What I have in
main() is the following:
int main(int argc, char *argv[])
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// NSApplicationLoad();
[NSApplication sharedApplication];
NSDictionary* dict = [[NSBundle mainBundle] infoDictionary];
[NSBundle loadNibNamed:[dict objectForKey:@"NSMainNibFile"]
owner:NSApp];
[NSThread detachNewThreadSelector:@selector(run:)
toTarget:[ThreadClass class]
withObject:nil];
assert([NSThread isMultiThreaded]);
openWindow();
// ThreadedWindow* twin = [[ThreadedWindow alloc] start];
[NSApp run];
[pool release];
return 0;
}
ThreadClass has a method +(void)run: that does nothing. It just "promptly
exits" as the documentation suggests. ThreadedWindow is a subclass of
NSObject where I am doing the work of opening an NSWindow and running
another run loop:
@implementation ThreadedWindow
-(id) start
{
[NSThread detachNewThreadSelector:@selector(controlLoop:)
toTarget:self
withObject:nil];
return self;
}
-(void) controlLoop:(id) obj
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
mRunning = true;
openWindow();
NSDate* date = [NSDate date];
do
{
date = [date addTimeInterval:0.5];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:date];
}
while ( mRunning );
[pool release];
}
@end
When the NSWindow instance is created, I set its content view and first
responder to a subclass of NSView that calls NSLog() for keyboard and mouse
events. All of this is in my helper function openWindow() so that I can call
it from the primordial thread or from one of my spawned threads.
Anyway, the main() from above works fine. The window that it opens receives
events correctly, and the main menu behaves. If I change it so that the call
to NSApplicationLoad() is uncommented, the creation of the ThreadedWindow is
uncommented, and the call to openWindow() is commented out, I get the window
processing events correctly in a thread, but there are basically two main
menus. If I change it again so that the call to NSApplicationLoad() is after
the call to [NSApplication sharedApplication], then the main menu behaves
again, but my window spawned from the thread stops receiving events.
> --
>
> Now, given that you state that your multithreading code stops working
> after you no longer call NSApplicationMain(), it is very likely that you
> haven't constructed the appkit's main event loop -- the runloop running
> on the main thread that handles all AppKit events -- correctly.
I was referring to NSApplicationLoad(), not NSApplicationMain(). I have not
been calling NSApplicationMain() at all.
> It isn't clear why you are mixing Carbon and Cocoa. Is your C++
> framework a Carbon framework? In any case, you can mix Carbon and
> Cocoa, but it is tricky. There is documentation on the
> http://developer.apple.com/ site.
I didn't intend to mix Carbon and Cocoa. As I said in my previous post, I
read that NSApplicationLoad() is needed in order to allow Carbon code to
utilize Cocoa. My goal here is not to use Carbon at all.
Ultimately, this is all an experiment because I want to learn more about
Objective-C, Objective-C+=, and Cocoa and because I want to improve the use
of the C++ software to which I have referred on Mac OS X. I'm quite thankful
to Apple for the availability of X11 for OS X because this particular
software would not work without it, but I'd like not to be dependent on X11
for OS X usage. If Cocoa doesn't end up working out, I'll most likely have
to go the Carbon route. Cocoa just seems like more fun. :)
-Patrick
--
Patrick L. Hartling | VP Engineering, Infiscape Corp.
PGP: http://tinyurl.com/2oum9 | http://www.infiscape.com/
Attachment:
signature.asc
Description: OpenPGP digital signature
_______________________________________________
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