NSProgressIndicator, runModalForWindow, detachNewThreadSelector -> Not good...
NSProgressIndicator, runModalForWindow, detachNewThreadSelector -> Not good...
- Subject: NSProgressIndicator, runModalForWindow, detachNewThreadSelector -> Not good...
- From: Dix Lorenz <email@hidden>
- Date: Tue, 4 Apr 2006 10:42:54 +0200
Hi,
I have a problem showing a very simple Window with a progress bar, it
has me stumped. This is my WindowController:
@interface Dialog_ProgressTask : NSWindowController
{
IBOutlet NSProgressIndicator *mProgressIndicator;
IBOutlet NSTextField *mStatusField;
IBOutlet NSButton *mCancelButton;
DLProgressTask *mTask;
}
- (id)initWithTask:(DLProgressTask *)inTask;
- (void)execute:(id)inArgument;
- (void)updateStatus:(NSTimer*)inTimer;
@implementation Dialog_ProgressTask
- (id)initWithTask:(DLProgressTask *)inTask
{
if ((self = [super initWithWindowNibName:@"Dialog_ProgressTask"])) {
mTask = inTask;
}
return self;
}
- (void)execute:(id)inArgument
{
mTask->Execute();
}
- (void)updateStatus:(NSTimer*)inTimer
{
#pragma unused (inTimer)
if (!mTask)
return;
if (mTask->isFinished()) {
mTask = NULL;
[NSApp abortModal];
return;
}
DLDouble theValue = mTask->CompletedPart();
[mProgressIndicator setDoubleValue:theValue];
}
@end
This is the calling function:
void mM4Dialog_RunProgressTask(DLProgressTask *inTask)
{
Dialog_ProgressTask *theController = [[Dialog_ProgressTask alloc]
initWithTask:inTask];
NSTimer *theTimer = [[NSTimer
timerWithTimeInterval:(NSTimeInterval)0.2
target:theController
selector:@selector(updateStatus:)
userInfo:nil
repeats:YES] retain];
[[NSRunLoop currentRunLoop] addTimer:theTimer
forMode:NSModalPanelRunLoopMode];
[NSThread detachNewThreadSelector:@selector(execute:)
toTarget:theController withObject:NULL];
int theResult = [NSApp runModalForWindow:[theController window]];
[theTimer invalidate];
[theTimer release];
[theController release];
}
I am pretty sure retain/release for the NSTimer are not necessary,
but AFAIK they don't hurt either and removing it doesn't change
anything anyway. mTask->Execute() is pure C++, does not call any
Cocoa and is thread-safe. When the Task is finished, [NSApp
abortModal] gets called as it should be, the program is usable again,
the results show up, everything is great... Except that the window
with the ProgressIndicator is still there. After a while (sometimes
very soon, sometimes it takes a few seconds) the program crashes:
#0 0x909c0120 in objc_msgSend
#1 0x928e2c20 in __NSFireMainThreadPerform
#2 0x9078ef2c in __CFRunLoopPerformPerform
#3 0x9075ea68 in __CFRunLoopDoSources0
#4 0x9075df98 in __CFRunLoopRun
#5 0x9075da18 in CFRunLoopRunSpecific
#6 0x9317d1e0 in RunCurrentEventLoopInMode
#7 0x9317c874 in ReceiveNextEventCommon
#8 0x9317c6e0 in BlockUntilNextEventMatchingListInMode
#9 0x9367b104 in _DPSNextEvent
#10 0x9367adc8 in -[NSApplication
nextEventMatchingMask:untilDate:inMode:dequeue:]
#11 0x9367730c in -[NSApplication run]
#12 0x93767e68 in NSApplicationMain
#13 0x00005420 in main at main.m:13
What I really don't understand: if I remove the line
[mProgressIndicator setDoubleValue:theValue];
the whole thing works perfectly: The window is destroyed as soon as
it finishes and AFAICT the program is stable, I can call that routine
again and again, no problems. Of course the progessindicator isn't
updated, so it's not really a solution.
Also if I do not use detachNewThreadSelector to execute the task but
just call it from updateStatus the crash occurs if I also update the
ProgressIndicator.
Normally I would say the problem has to be in mTask->Execute(), but I
really doubt it. It is complicated code, no question, but so far it
has been very stable for me and the problem really only occurs when
mProgressIndicator is updated in any way (using it indeterminate or
using threaded animation doesn't change anything).
Somebody please tell I've done something very stupid in my code which
I just can't see...
Thanks,
Dix
_______________________________________________
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