GCD для выполнения задачи в главном потоке - PullRequest
216 голосов
/ 14 апреля 2011

У меня есть обратный вызов, который может прийти из любого потока. Когда я получаю этот обратный вызов, я хотел бы выполнить определенную задачу в главном потоке.

Нужно ли проверять, нахожусь ли я уже в главном потоке - или есть какой-либо штраф, если не выполнить эту проверку до вызова кода ниже?

dispatch_async(dispatch_get_main_queue(), ^{
   // do work here
});

Ответы [ 4 ]

141 голосов
/ 14 апреля 2011

Нет, вам не нужно проверять, находитесь ли вы уже в главном потоке.Отправляя блок в основную очередь, вы просто планируете, чтобы блок выполнялся последовательно в основном потоке, что происходит при запуске соответствующего цикла выполнения.

Если вы уже находитесь в основном потоке,поведение такое же: блок запланирован и выполняется при запуске цикла выполнения основного потока.

94 голосов
/ 18 ноября 2011

Для случая асинхронной отправки, который вы описали выше, вам не нужно проверять, находитесь ли вы в главном потоке.Как указывает Bavarious, это будет просто поставлено в очередь для запуска в главном потоке.

Однако, если вы попытаетесь сделать это с помощью dispatch_sync() и ваш обратный вызов находится в главном потоке, ваше приложение будеттупик в этой точке.Я описываю это в своем ответе здесь , потому что это поведение удивило меня при перемещении некоторого кода из -performSelectorOnMainThread:.Как я уже упоминал, я создал вспомогательную функцию:

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

, которая будет синхронно запускать блок в основном потоке, если используемый вами метод в данный момент не находится в основном потоке, а просто выполняетвстроенный блок, если это так.Вы можете использовать синтаксис, подобный следующему, чтобы использовать это:

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});
47 голосов
/ 17 января 2015

Как уже упоминалось в других ответах, 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 вам не поможет.

1 голос
/ 06 декабря 2015

Нет, вам не нужно проверять, находитесь ли вы в главном потоке. Вот как вы можете сделать это в 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

...