次のようなコードの場合:
// Code in some object that will do work for an application:
- (BOOL)shouldBeRunning
{
[lockRunning lock];
BOOL shouldBeRunning= shouldRun;
[lockRunning unlock];
return shouldBeRunning;
}
- (void)stopRunning
{
[lockRunning lock];
shouldRun= FALSE;
[lockRunning unlock];
}
- (void)threadEntryPoint:(id)object
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
// From an example I saw awhile back:
// A runloop with no sources returns immediately from runMode:beforeDate:
// That will wake up the loop and chew CPU. Add a dummy source to prevent it.
NSMachPort *dummyPort = [[NSMachPort alloc] init];
[runLoop addPort:dummyPort forMode:NSDefaultRunLoopMode];
[dummyPort release];
[pool release];
while ([self shouldBeRunning])
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
[loopPool drain];
}
}
- (BOOL)startRunning:(NSError **)errorPtr
{
[self stopRunning]; // Stop if we are already running.
[runWorker release];
runWorker= [[NSThread alloc] initWithTarget:self selector:@selector(threadEntryPoint:) object:nil];
if(!runWorker)
return (FALSE);
// Start up the thread.
shouldRun= TRUE;
[runWorker start];
return TRUE;
}
- (void)doLotsOfStuff
{
// Some operation that is long and intensive
// that should be done in the background.
// This function will call the app delegate, which will display the
// results. It will also notify the app on completion.
}
- (void)doStuff
{
// Commented out for illustrative purposes.
//[self startRunning]; // Fire thread up.
[self performSelector:@selector(doLotsOfStuff) onThread:runWorker withObject:nil waitUntilDone:NO];
}
// Out in the delegate:
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
// Do setup....
[workObject startRunning]; // Start the worker thread in the worker object.
}
- (void)buttonHandler:(id)sender
{
[workObject doStuff];
}
そのため、アプリケーションにはボタンがあります。ユーザーがそれを押すと、タスクがワーカー スレッドで実行されます。タスクはアプリケーションにフィードバックを提供します。この場合、ボタンはタスクが完了するまで無効になります。そのコードをすべて表示したくないだけです。
書かれたコードでは、ボタンを 1 回押すと、遅延なくタスクが実行されます。多くの場合、もう一度ボタンを押しても同じ結果が得られます。ただし、2 回目のプレス (ほとんどの場合 3 回目以降) では、タスクの実行が大幅に遅れることがあります。デバッグ ステートメントを挿入すると、コードがスレッドで performSelector を実行し、その後遅延が発生し、最後にタスクが実行されることがわかります。
スレッドを再作成する doStuff の行のコメントを外すと (applicationDidFinishLaunching の行が冗長になります)、もちろん、毎回完全に機能します。
私が知る限り、スレッドは応答しない状態になっています。
何が起こっているのかについてのアイデアはありますか? セットアップと処理コードに明らかな問題はありますか? 任意の入力をいただければ幸いです。