Разделы 7.6 и 7.10.
7.6. Асинхронное решение с помощью GCD задач, не связанных с пользовательским интерфейсом
Необходимо иметь возможность решать задачи, не связанные с пользовательским интерфейсом, с помощью GCD.
Вот здесь GCD и проявляется во всей красе: при асинхронном выполнении блоков кода в главной очереди, последовательных и параллельных очередях. Не сомневаюсь, что, дочитав этот раздел, вы будете совершенно убеждены в том, что будущее многопоточных приложений неразрывно связано с GCD, который в перспективе заменит потоки, применяемые в современных программах.
Чтобы выполнять в диспетчерской очереди асинхронные задачи, следует пользоваться одной из следующих функций:
• dispatch_async — отправляет блоковый объект в диспетчерскую очередь (и объект и очередь указываются в соответствующих параметрах) для асинхронного выполнения;
• dispatch_async_f — отправляет в диспетчерскую очередь функцию языка C вместе со ссылкой на контекст (все три элемента указываются в соответствующих параметрах) для асинхронного выполнения.
Рассмотрим реальный пример. Напишем приложение для iOS, которое позволит нам скачивать изображение из Интернета по имеющейся гиперссылке (URL). После завершения загрузки наша программа должна отобразить изображение для пользователя. Далее приведен план работы и описано, как будут применены те или иные концепции, связанные с GCD, которые мы уже успели изучить.
1. Мы собираемся асинхронно запускать блоковый объект в параллельной очереди.
2. В ходе выполнения этого блока будем однократно (синхронно) запускать другой блоковый объект. Его мы будем использовать для скачивания изображения по URL, при этом будет применяться функция dispatch_sync. Мы поступаем именно так, поскольку хотим, чтобы обработка остального кода, стоящего в данной параллельной очереди, не начиналась, пока не загрузится изображение. В результате мы заставляем подождать только одну параллельную очередь, а не все остальные очереди. Если синхронно скачивать файл по URL из асинхронного блока кода, мы заблокируем лишь очередь, обрабатывающую синхронную функцию, но не главный поток. Вся операция так и остается асинхронной с точки зрения главного потока. Мы решаем основную задачу: при загрузке изображения главный поток не блокируется.
3. Сразу после того, как загрузка изображения завершится, мы синхронно выполним блоковый объект в главной очереди (см. раздел 7.4), чтобы отобразить картинку в пользовательском интерфейсе.
Каркас для планируемой программы совершенно прост:
— (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear: animated];
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block UIImage *image = nil;
dispatch_sync(concurrentQueue, ^{
/* Здесь скачивается изображение. */
});
dispatch_sync(dispatch_get_main_queue(), ^{
/* Здесь мы демонстрируем изображение пользователю и делаем это
в главной очереди. */
});
});
}
Второй вызов к dispatch_sync, после которого отобразится картинка, будет выполняться в очереди после первого синхронного вызова, который обеспечивает загрузку изображения. Именно этого мы и добивались, поскольку нам необходимо дождаться, пока изображение загрузится полностью, и только после этого мы сможем отобразить его для пользователя. Итак, после завершения скачивания изображения мы выполняем второй блоковый объект, но на этот раз — в главной очереди.
Скачаем изображение и отобразим его для пользователя. Это мы сделаем в методе экземпляра viewDidAppear:, относящемся к контроллеру вида, который в данный момент отображается в приложении для iPhone:
— (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear: paramAnimated];
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block UIImage *image = nil;
dispatch_sync(concurrentQueue, ^{
/* Здесь скачивается изображение. */
/* Изображение iPad с сайта Apple. Гиперссылка слишком длинная,
поэтому ее нужно правильно разбить на две строки. */
NSString *urlAsString = @" http://images.apple.com/mobileme/features"\
«/images/ipad_findyouripad_201 00518.jpg»;
NSURL *url = [NSURL URLWithString: urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL: url];
NSError *downloadError = nil;
NSData *imageData = [NSURLConnection
sendSynchronousRequest: urlRequest
Читать дальше
Конец ознакомительного отрывка
Купить книгу