Когда использовать 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). Но вам все равно лучше подчиниться документу:)