views:

111

answers:

1

I've stumbled upon a problem in the application I'm developing using cocoa. I need to do some processing, and I'm doing it on a separate thread. I'm doing this so I can display the progress using a NSProgressIndicator and not hang the main thread. (The user can cancel the execution if he/she wants).

It's almost working perfectly, But there's a problem: The processing produces a lot of files, and if one or more of these files already exists, I would like to ask the user if it's OK to overwrite them before actually doing so. So I tried using NSRunAlertPanel() from the processing thread.

It works some of the times. Other times, the Alert Panel will flicker, close for no particular reason before I can click on it, or not appear at all. So I figured that NSRunAlertPanel() is probably not thread safe, and this is hapenning due to race conditions.

I would like to know: Is there a way I can fix this other than constantly polling the processing thread for it's progress from the main thread using a timer?

Is using the GUI from any thread other the main one inherently unsafe?

Thanks in advance.

EDIT: I'm following Marc's instructions but there's still something wrong, because my NSAlerts (which I'm also using now) are still disappearing. Here's my processing thread.

- (void)doProcess:(id)param
{
    // ...
    [self performSelectorOnMainThread:@selector(askForConfirmation) withObject:nil waitUntilDone:YES];
    // ...
}

Then on my main thread:

- (void)askForConfirmation
{
    [[NSAlert alertWithMessageText:@"Test." defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"Testing."] runModal];
}

- (IBAction)startProcessing:(id)sender
{
    // ...
    [NSThread detachNewThreadSelector:@selector(doProcess:) toTarget:self withObject:nil];
    // ...
}
+1  A: 

The main thread is the GUI thread. You should not do any GUI stuff on any background threads. That being said, you can write a method that calls NSRunAlertPanel() and then call your method by using one of NSObject's performSelectorOnMainThread: methods.

To check if you are currently executing on the main thread, you can just call [NSThread isMainThread].

Marc W
Not to mention that if you're not targeting anything under 10.3, it's recommended to use `NSAlert` instead.
Wevah
There's no need to check whether you're on the main thread if you're going to perform something on the main thread. The `performSelectorOnMainThread:` methods work from the main thread as well, and simpler code is better.
Peter Hosey