Оставьте NSThread живым и запустите на нем NSRunLoop - PullRequest
22 голосов
/ 08 июня 2011

Итак, я запускаю новый NSThread, который хочу использовать позже, вызывая performSelector:onThread:.... Насколько я понимаю, вызов этого метода добавляет этот вызов к циклу выполнения в этом потоке, поэтому на следующей итерации он извлекает все эти вызовы и затем вызывает их до тех пор, пока не останется ничего для вызова. Поэтому мне нужна такая функциональность, готовая к работе пустая нить, которую я могу просто вызвать. Мой текущий код выглядит так:

   - (void)doInitialize
   {
       mThread =  [[NSThread alloc] initWithTarget:self selector:@selector(runThread) object:nil];
       [mthread start];
   }

   - (void)runThread
   {
       NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];

       // From what I understand from the Google machine is that this call should start the
       // runloop on this thread, but it DOESN'T. The thread dies and is un-callable
       [[NSRunLoop currentRunLoop] run];

       [pool drain];
   }

   - (void)scheduleSomethingOnThread
   {
       [self performSelector:@selector(hardWork) onThread:mThread withObject:nil waitUntilDone:NO];
   }

Но поток не поддерживается, и executeSelector: onThread ничего не делает. Как мне поступить правильно?

Ответы [ 2 ]

15 голосов
/ 08 июня 2011

Для запуска цикла требуется как минимум один «источник ввода». Основной цикл выполнения выполняется, но вы должны добавить источник вручную, чтобы метод вспомогательного цикла выполнения -run сделал что-либо. Есть некоторая документация по этому здесь .

Один наивный способ заставить это работать - просто поместить [[NSRunLoop currentRunLoop] run] в бесконечный цикл; когда есть что-то сделать, он сделает это и немедленно вернется в противном случае. Проблема в том, что поток займет приличное количество процессорного времени, просто ожидая, что что-то произойдет.

Другое решение - установить NSTimer в этом цикле выполнения, чтобы поддерживать его в рабочем состоянии.

Но, если возможно, вы должны использовать механизм, предназначенный для такого рода вещей. Если возможно, вы можете использовать NSOperationQueue для фоновых операций.

8 голосов
/ 25 февраля 2013

этот кусок кода должен заставить поток ждать вечно

BOOL shouldKeepRunning = YES;        // global
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; // adding some input source, that is required for runLoop to runing
while (shouldKeepRunning && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); // starting infinite loop which can be stopped by changing the shouldKeepRunning's value
...