Когда использовать dispatch_get_main_queue

Я узнал одно глобальное правило в iOS -> никогда не блокировать основной поток. Однако несколько раз я сталкивался с фрагментами открытого исходного кода, где это правило нарушалось.

Вот два таких примера:

Следующая функция взята с https://github.com/piwik/piwik-sdk-ios/blob/master/PiwikTracker/PiwikTracker.m

- (void) startDispatchTimer {

  // Выполнить в цикле выполнения основного потока
  __ слабый typeof(self)weakSelf = self;
  dispatch_async(dispatch_get_main_queue(), ^{

    [weakSelf stopDispatchTimer];

    // Если интервал отправки равен 0) {

      // Запуск по таймеру
      strongSelf.dispatchTimer = [NSTimer scheduleTimerWithTimeInterval:weakSelf.dispatchInterval
                                                                Цель: weakSelf
                                                              селектор:@selector(отправка:)
                                                              USERINFO: ноль
                                                               не повторяется:NO];

      NSLog(@"Таймер отправки запущен с интервалом%f", weakSelf.dispatchInterval);

    }

  });

}

В приведенном выше коде я пытался понять, почему основной поток требуется для объекта таймера. Нечто подобное не связано с пользовательским интерфейсом и все еще выполняется в основном потоке

Еще один пример этого - известная сетевая библиотека MKNetworkKit . Где следующий код находится в методе запуска NSOperation. https://github.com/MugunthKumar/MKNetworkKit/blob/master/MKNetworkKit/MKNetworkOperation.m

dispatch_async (dispatch_get_main_queue (), ^ {
      self.connection = [[NSURLConnection alloc] initWithRequest: self.request
                                                        Делегат: самостоятельно
                                                не startImmediately:NO];

      [self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
                                 forMode:NSRunLoopCommonModes];

      [self.connection start];
    });

Поэтому мои вопросы: почему люди используют основной поток для выполнения операций, не связанных с пользовательским интерфейсом, и какую пользу это дает. Оно может не заморозить ваше приложение, если вы не держитесь за него, но зачем рисковать.

1 ответ

Решение

Оба примера используют методы NSRunLoop прямо или косвенно. В этих случаях вы должны вызывать методы из потока, который выполняет целевой NSRunLoop. Таким образом, вам нужно dispatch_get_main_queue().

Посмотрите на яблочный документ о NSRunLoop https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/classes/nsrunloop_class/reference/reference.html

Предупреждение: класс NSRunLoop обычно не считается поточно-ориентированным, и его методы должны вызываться только в контексте текущего потока. Никогда не пытайтесь вызывать методы объекта NSRunLoop, запущенного в другом потоке, так как это может привести к неожиданным результатам.

Кстати, NSRunLoop, похоже, использует CFRunLoop в Core Foundation, а Core Foundation был выпущен по лицензии Apple с открытым исходным кодом.

http://opensource.apple.com/source/CF/CF-855.17/CFRunLoop.c

Кажется, CFRunLoop является поточно-ориентированным (мы можем увидеть много комбинаций __CFRunLoopLock и __CFRunLoopUnlock). Но вам все равно лучше подчиниться документу:)

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