Подтвердить что ты не робот

Почему это dispatch_sync() вызывает замораживание?

Я использую среду тестирования Kiwi для проверки метода проверки подлинности в своем приложении. Тест зависает при вызове dispatch_sync, который выглядит следующим образом:

dispatch_queue_t main = dispatch_get_main_queue();
dispatch_sync(main, ^
                  {
                      [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
                  });

Я хотел бы знать, почему он зависает там, если у кого есть какие-то намеки.

4b9b3361

Ответ 1

Во второй части вашего вопроса относительно намека на замораживание:

При вызове dispatch_sync в очереди всегда убедитесь, что эта очередь уже не является текущей очередью (dispatch_get_current_queue()). Поскольку dispatch_sync будет помещать в очередь ваш блок в очереди, переданной как первый параметр, а затем будет ждать выполнения этого блока перед продолжением.

Итак, если dispatch_get_current_queue() и очередь, в которую вы вставляете свой блок, одинаковы, а именно главная очередь в вашем случае, основная очередь будет блокировать вызов dispatch_sync до тех пор, пока... главная очередь не будет выполнена блоком, но он не может, поскольку очередь заблокирована, , и у вас есть красивый тупик здесь.

Одно решение ([EDIT] до iOS6):

dispatch_queue_t main = dispatch_get_main_queue();
dispatch_block_t block = ^
              {
                  [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
              };
if (dispatch_get_current_queue() == main)
  block(); // execute the block directly, as main is already the current active queue
else
  dispatch_sync(main, block); // ask the main queue, which is not the current queue, to execute the block, and wait for it to be executed before continuing

[РЕД.] Будьте осторожны, dispatch_get_current_queue() используется только для целей отладки и никогда в производстве. Фактически, dispatch_get_current_queue устарел с iOS6.1.3.

Если вы находитесь в конкретном случае основной очереди (которая связана только с основным потоком), вы можете вместо этого проверить [NSThread isMainThread], как это было предложено в @смыслах.


Кстати, вы уверены, что вам нужно dispatch_sync в вашем случае? Я предполагаю, что вы отправляете свое уведомление немного позже, избегая блокировки до его отправки, приемлемо в вашем случае, поэтому вы можете также рассмотреть возможность использования dispatch_async (вместо использования dispatch_sync и необходимости условия сравнения в очереди), что также избегайте проблем с блокировкой.

Ответ 2

dispatch_get_current_queue() устарел, начиная с iOS 6, а dispatch_get_current_queue() == dispatch_get_main_queue() оказался false, а в основном потоке в iOS 6.1.3.

В iOS 6 и далее просто выполните:

dispatch_block_t block = ^
{
    <your code here>
};

if ([NSThread isMainThread])
{
    block();
}
else
{
    dispatch_sync(dispatch_get_main_queue(), block);
}