Я столкнулся со сценарием, в котором у меня был обратный вызов делегата, который мог произойти либо в основном потоке, либо в другом потоке, и я не знал, какой до среды выполнения (используя 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, или есть что-то, чего мне не хватает в документах?