Как мне ждать, пока NSOperationQueue не закончится в модульном тесте? - PullRequest
1 голос
/ 01 сентября 2010

Проблема

  • У меня есть NSOperationQueue с именем logEntryGeneratorQueue
  • Я хочу дождаться завершения всех операций в очереди

Если я использую:

[logEntryGeneratorQueue waitUntilAllOperationsAreFinished];

, то это нормально работает, если поток, добавляющий в очередь, находится в самом фоне.

Однако, если я запускаю этот код черезмодульный тест, он будет работать в основном потоке.Поэтому я пришел к этому «решению», которое мне действительно не нравится:

if ([NSThread isMainThread]) {
    while ([[logEntryGeneratorQueue operations] count] > 0) {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    }
} else {
    [logEntryGeneratorQueue waitUntilAllOperationsAreFinished];
}

Это всегда было далеко не идеально, но всегда работало нормально на 10.5.Однако теперь я обновил свой проект до использования 10.6 SDK, и это ломается.

На одном тесте он фактически завершает тест до его завершения.Я понятия не имею, почему - я предполагаю, что это как-то связано с тем, как NSOperationQueues работает по-разному в 10.6 - теперь они используют GCD.

То, что я пробовал

Я пытался заменить runUntilDate на sleep, что, как я и думал, означает, что каждый тест останавливается навсегда, когда он попадает сюда.

Мой вопрос

Есть ли лучшийспособ ждать завершения NSOperationQueue в основном потоке?Если нет, как я могу заставить этот код работать под 10.6?

Ответы [ 4 ]

2 голосов
/ 10 сентября 2010

Решение

Я понял, что мой код находится в вечном цикле, потому что я вызывал mergeChangesFromContextDidSaveNotification в главном потоке, в то же время ожидая завершения очереди в главном потоке,И поскольку изменения слияния были вызваны после waitUntilAllOperationsAreFinished, оно так и не было выполнено.

Я думаю, что ответ состоит в том, чтобы изменить место, откуда я запускаю NSOperationQueues.Я не должен запускать NSOperationQueue, который имеет дело с основными данными в основном потоке.И я не думаю, что мне действительно следует запускать этот интенсивный материал в главном потоке по соображениям производительности.

1 голос
/ 01 сентября 2010

Я согласен с Максом: -waitUntilAllOperationsAreFinished должно работать.Ваша очередь приостановлена?

1 голос
/ 01 сентября 2010

Я бы сказал, что waitUntilAllOperationsAreFinished должен работать как и ожидалось на 10.6, независимо от того, из какого потока это называется.Поскольку в очередях операций в 10.6 больше не используется цикл выполнения, нет смысла не блокировать и запускать цикл.Вы пытались просто позвонить waitUntilAllOperationsAreFinished =

0 голосов
/ 31 декабря 2011

ИМХО, вам нужно учитывать вероятность того, что waitUntilAllOperationsAreFinished может зависнуть, если одна (или все) его операция выполняется с использованием основного потока приложения в качестве носителя. Пример: ваша nsoperation не является параллельным и использует цикл автообновления glkview для анимации и обновления собственного состояния, и ваша операция выполняется (и операция помечена как завершенная), только если основной поток имеет шанс на работу. Но он не может, поскольку заблокирован в ожидании завершения этих операций.

...