Я столкнулся с сценарием, когда у меня был обратный вызов делегата, который мог произойти либо в основном потоке, либо в другом потоке, и я бы не знал, до какого времени он будет работать (используя StoreKit.framework
).
У меня также был UI-код, который мне нужно было обновить в этом обратном вызове, который должен был произойти до выполнения функции, поэтому моя первоначальная мысль заключалась в том, чтобы иметь такую функцию:
-(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, или есть что-то, что мне не хватает в документах?