GCD для выполнения задачи в главном потоке
У меня есть обратный вызов, который может прийти из любого потока. Когда я получаю этот обратный вызов, я хотел бы выполнить определенную задачу в главном потоке.
Нужно ли проверять, нахожусь ли я уже в главном потоке - или есть какой-либо штраф, если не выполнить эту проверку до вызова кода ниже?
dispatch_async(dispatch_get_main_queue(), ^{
// do work here
});
4 ответа
Нет, вам не нужно проверять, находитесь ли вы уже в главном потоке. Отправляя блок в основную очередь, вы просто планируете последовательное выполнение блока в главном потоке, что происходит при запуске соответствующего цикла выполнения.
Если вы уже находитесь в главном потоке, поведение такое же: блок запланирован и выполняется при запуске цикла выполнения основного потока.
Для случая асинхронной отправки, который вы описали выше, вам не нужно проверять, находитесь ли вы в главном потоке. Как указывает Bavarious, он просто будет поставлен в очередь для запуска в главном потоке.
Тем не менее, если вы попытаетесь сделать выше, используя dispatch_sync()
и ваш обратный вызов находится в главном потоке, ваше приложение будет заблокировано в этот момент. Я опишу это в своем ответе здесь, потому что это поведение удивило меня при перемещении некоторого кода из -performSelectorOnMainThread:
, Как я уже упоминал, я создал вспомогательную функцию:
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
который будет синхронно запускать блок в главном потоке, если метод, в котором вы находитесь, в данный момент отсутствует в главном потоке, и просто выполняет встроенный блок, если он есть. Вы можете использовать синтаксис, подобный следующему, чтобы использовать это:
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
Как уже упоминалось в других ответах, 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 не поможет вам.
Нет, вам не нужно проверять, находитесь ли вы в главном потоке. Вот как вы можете сделать это в 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