Основной поток зависает на неопределенное время в ожидании отмены операций NSOperationQueue [Только на устройстве!] - PullRequest
3 голосов
/ 16 декабря 2009

У меня в главном потоке NSOperationQueue выполняется набор NSOperations (макс. Одновременный набор 1), которые я хочу иметь возможность отменить в любое время.Когда я нажимаю кнопку, я приказываю очереди отменить все операции и дождаться завершения.Это должно привести к зависанию основного потока до тех пор, пока очередь операций не опустеет, однако мой главный поток зависает бесконечно.

Вот код, который я использую для его остановки:

...
[myQueue cancelAllOperations];
[myQueue waitUntilAllOperationsAreFinished];
return YES; // This line never gets called

Примечание: Мне нужно использовать waitUntilAllOperationsAreFinished, поскольку дальнейшие процессы требуют, чтобы очередь была пустой.

Странно то, что это происходит только на устройстве.При работе в симуляторе он работает как положено.

Я наблюдал за точками останова и могу следить за текущей выполняемой операцией до ее завершения.Он обнаруживает [self isCancelled], останавливает свою работу и проникает в конец метода main.Я вижу, что ничто в операции не приводит к зависанию, и после отмены всех операций ни одна из других операций не должна начинаться, и очередь должна заканчиваться.Я проверил, добавив точки останова, и ни одна из других операций не началась.

Почему это происходит?

Ответы [ 3 ]

8 голосов
/ 16 декабря 2009

В какой-либо из ваших операций (или в любой другой теме) вы используете -performSelectorOnMainThread:withObject:waitUntilDone:? -waitUntilAllOperationsAreFinished будет блокировать любой вызванный поток до тех пор, пока все операции не будут завершены. Скорее всего, если вы вызываете это, когда приложение завершается, этот поток будет основным потоком. Если основной поток заблокирован и одна из операций использует -performSelectorOnMainThread:withObject:waitUntilDone:, ваше приложение будет зависать, потому что операция никогда не завершится.

Раньше со мной случалось именно это. К сожалению, это довольно сложно обойти.

5 голосов
/ 16 декабря 2009

Вы никогда не должны блокировать основной поток. Он обрабатывает все ваши обновления пользовательского интерфейса, с одной стороны, с другой, как вы уже заметили, вам удалось создать тупик.

Вместо этого попробуйте создать метод, подобный:

- (void) notifyOnFinish
{
   [myQueue waitUntilAllOperationsAreFinished];
   [self performSelectorOnMainThread:(queueEmpty) withObject:nil waitUntilDone:NO];
}

Тогда, где у вас есть код, звоните:

[myQueue cancelAllOperations];
[self performSelectorInBackground:@selector(notifyOnFinish) withObject:nil];

А в методе queueEmpty вы просто делаете все, что хотите, когда очередь очищается.

По сути, просто создайте фоновый поток для блокировки вместо основного потока.

0 голосов
/ 16 декабря 2009

Возможно, waitUntilAllOperationsArefFinished вызывает блокировку ... Может быть, все операции отменяются и заканчиваются перед вызовом waitUntilAllOperationsArefFinished, а затем очередь остается в режиме ожидания, ожидая завершения операций, которые уже завершены ...?

Я не знаю это точно, но, возможно, постараюсь не звонить waitUntilAllOperationsArefFinished.

...