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

Другие вопросы по тегам