简体   繁体   中英

Running a Cocoa GUI in a non-main thread

I am having a gui/threading related problem in developing a cocoa user interface. The application is designed like this:

Main Thread (#1): parses arguments, loads plugins, etc.

Gui thread (#?): launches the gui, handles events, etc. Its the gui thread.

The Cocoa framework is non-thread safe, but enforces one rule, the GUI must run on the main thread. A assertion is used to check this. To try to go around this I implemented the run method myself (code below) following this - http://cocoawithlove.com/2009/01/demystifying-nsapplication-by.html - guide. But I am missing something. A window is opened, but stays blank (completely white). Although if I make the call in the main thread it works perfectly.

So basically I need to figure out what's missing.

- (void)run
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [self finishLaunching];

    shouldKeepRunning = YES;
    do
    {
        [pool release];
        pool = [[NSAutoreleasePool alloc] init];

        NSEvent *event =
            [self
                nextEventMatchingMask:NSAnyEventMask
                untilDate:[NSDate distantFuture]
                inMode:NSDefaultRunLoopMode
                dequeue:YES];

        [self sendEvent:event];
        [self updateWindows];
    } while (shouldKeepRunning);

    [pool release];
}

- (void)terminate:(id)sender
{
    shouldKeepRunning = NO;
}

Don't. This approach will never work. Even if you fix your current problem (the window not drawing) you'll immediately run into another obscure, impossible-to-fix problem, and another, and another. Cocoa expects the GUI thread to be the main thread, end of story.

Why not reverse the problem? Have the main thread spawn a thread (let's call this the app thread), then block before spawning the GUI. The app thread will parse arguments, load plugins, etc. After it's initialization is done, the app thread will signal the main thread to go ahead and launch the GUI.

Do all in the background thread except updating the GUI. I see that you have only a line where you need to update the GUI. So do it the way you're doing it, except that you execute all GUI updates in the main thread:

dispatch_async(dispatch_get_main_queue(), ^
{
    [self updateWindows];
});

Now I don't know what's updateWindows, I assumed that this wouldn't create a race condition.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM