GCD для выполнения задачи в основной теме
У меня есть обратный вызов, который может возникнуть из любого потока. Когда я получаю этот обратный вызов, я хотел бы выполнить определенную задачу в основном потоке.
Нужно ли мне проверять, есть ли я уже в основном потоке, или есть ли какой-либо штраф, не выполняя эту проверку до вызова кода ниже?
dispatch_async(dispatch_get_main_queue(), ^{
// do work here
});
Ответы
Ответ 1
Нет, вам не нужно проверять, уже ли вы на основном потоке. Отправляя блок в основную очередь, вы просто планируете блок, который будет выполняться последовательно по основному потоку, который происходит, когда выполняется соответствующий цикл цикла.
Если вы уже находитесь в основном потоке, поведение будет одинаковым: блок запланирован и выполняется при запуске цикла запуска основного потока.
Ответ 2
Для случая асинхронной отправки, описанного выше, вам не нужно проверять, находитесь ли вы в основном потоке. Как указывает Bavarious, это будет просто поставлено в очередь для запуска в основном потоке.
Однако, если вы попытаетесь сделать это, используя dispatch_sync()
, и ваш обратный вызов будет включен в основной поток, ваше приложение будет блокировано в этой точке. Я описываю это в своем ответе здесь, потому что это поведение меня удивило, когда я переместил код из -performSelectorOnMainThread:
. Как я упоминаю там, я создал вспомогательную функцию:
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
который будет запускать блок синхронно в основном потоке, если метод, в котором вы находитесь, в настоящее время не находится в основном потоке и просто выполняет блок inline, если он есть. Для этого можно использовать синтаксис следующего вида:
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
Ответ 3
Как упоминалось в других ответах, dispatch_async из основного потока прекрасен.
Однако, в зависимости от вашего варианта использования, есть побочный эффект, который вы можете считать недостатком: поскольку блок запланирован в очереди, он не будет выполняться до тех пор, пока управление не вернется в цикл выполнения, который будет иметь эффект задержки выполнения вашего блока.
Например,
NSLog(@"before dispatch async");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"inside dispatch async block main thread from main thread");
});
NSLog(@"after dispatch async");
Будет распечатан:
before dispatch async
after dispatch async
inside dispatch async block main thread from main thread
По этой причине, если вы ожидали, что блок будет выполняться между внешними NSLog, dispatch_async не поможет вам.
Ответ 4
Нет, вам не нужно проверять, находитесь ли вы в основном потоке. Вот как вы можете это сделать в Swift:
runThisInMainThread { () -> Void in
runThisInMainThread { () -> Void in
// No problem
}
}
func runThisInMainThread(block: dispatch_block_t) {
dispatch_async(dispatch_get_main_queue(), block)
}
Он включен как стандартная функция в моем репо, проверьте его: https://github.com/goktugyil/EZSwiftExtensions