Да, вы правы, что хотите использовать runloop, вам не хватает только того, как все это настроить. Я собираюсь изменить ваш пост и объяснить, что происходит. Не волнуйтесь, если это вас пугает, это сложно, и есть некоторые ошибки, о которых вы узнаете только из опыта
- (IBAction) startThread:(id)sender
{
self.renderThreadMode = render_run;
label.text = @"doing stuff";
self.backgroundThread = [[NSThread alloc] initWithTarget:self selector:@selector(keepDoingStuff) object:nil];
[self.backgroundThread start];
}
//Okay, this is where we start changing stuff
- (void)keepDoingStuff
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//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.
NSRunLoop *runLopp = [NSRunLoop currentRunLoop];
NSMachPort *dummyPort = [[NSMachPort alloc] init];
[runLoop addPort:dummyPort forMode:NSDefaultRunLoopMode];
[dummyPort release];
[pool release];
while (1)
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
[loopPool drain];
}
}
Хорошо, на этом этапе вы должны посмотреть на приведенный выше код и подумать: «Ну, это может быть хороший спящий поток, но он ничего не делает. И это правда, но так как он имеет активный runloop мы можем сделать все, что основано на runloop, включая executeSelector: onThread: withObject: waitUntilDone:
- (void) doStuffOnBackgroundThread
{
[self performSelector:@selector(doStff) onThread:self.backgroundThread withObject:nil waitUntilDone:NO];
}
Когда вы вызываете вышеупомянутый метод в вашем основном потоке (или любом другом потоке), он будет маршалировать различные аргументы и ставить в очередь цикл выполнения указанного потока, вызывая его по мере необходимости. В этом случае это приведет к пробуждению self.backgroundThread из runMode: beforeDate:, выполните -doStuff, затем вернитесь назад к циклу и снова перейдите в режим ожидания в runMode: beforeDate :. Если вы хотите иметь возможность разорвать поток, вы можете установить переменную в цикле while, как вы это делали в своем коде, хотя помните, что поток пропадет, если он спит, если вы его не разбудите, поэтому, вероятно, лучше всего инкапсулировать что в методе, который устанавливает переменную управления с помощью executeSelector: onThread: withObject: waitUntilDone :, в качестве плюса, это будет означать, что переменная будет когда-либо устанавливаться только из фонового потока, что упрощает проблемы синхронизации.
Хорошо, я думаю, что это решит вашу проблему, так что пора сделать обязательный плагин: вы уверены, что хотите делать это с потоками? NSOperation и NSOperationQueue могут быть намного более простым решением, которое позаботится обо всех проблемах с многопоточностью, если все, что вам нужно сделать, - это иногда ставить в очередь некоторые данные для обработки. Они будут планировать работу, управлять зависимостями и создавать / разрушать потоки, а также заботиться обо всех вещах runloop wake / sleep.