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