Почему мы не можем использовать dispatch_sync в текущей очереди?

Я столкнулся со сценарием, в котором у меня был обратный вызов делегата, который мог произойти либо в основном потоке, либо в другом потоке, и я не знал, какой до среды выполнения (используя StoreKit.framework).

У меня также был код пользовательского интерфейса, который мне нужно было обновить в этом обратном вызове, который должен был произойти до выполнения функции, поэтому моя первоначальная мысль заключалась в том, чтобы иметь функцию, подобную этой:

-(void) someDelegateCallback:(id) sender
{
    dispatch_sync(dispatch_get_main_queue(), ^{
        // ui update code here
    });

    // code here that depends upon the UI getting updated
}

Это отлично работает, когда она выполняется в фоновом потоке. Однако при выполнении на основном потоке программа заходит в взаимоблокировку.

Это само по себе кажется мне интересным, если я прочитаю документы для dispatch_syncправильно, то я ожидаю, что он просто выполнит блок напрямую, не беспокоясь о планировании его в runloop, как сказано здесь:

В качестве оптимизации эта функция вызывает блок в текущем потоке, когда это возможно.

Но это не слишком большая проблема, это просто означает немного больше набора текста, что привело меня к следующему подходу:

-(void) someDelegateCallBack:(id) sender
{
    dispatch_block_t onMain = ^{
        // update UI code here
    };

    if (dispatch_get_current_queue() == dispatch_get_main_queue())
       onMain();
    else
       dispatch_sync(dispatch_get_main_queue(), onMain);
}

Однако,это кажется немного обратным. Была ли это ошибка в создании GCD, или есть что-то, чего мне не хватает в документах?

57
задан Jano 31 March 2013 в 02:52
поделиться