Шрифт:
Интервал:
Закладка:
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
returningResponse: nil
error:&downloadError];
if (downloadError == nil &&
imageData!= nil){
image = [UIImage imageWithData: imageData];
/* Изображение у нас есть. Теперь можно его использовать. */
}
else if (downloadError!= nil){
NSLog(@"Error happened = %@", downloadError);
} else {
NSLog(@"No data could get downloaded from the URL.");
}
});
dispatch_sync(dispatch_get_main_queue(), ^{
/* Здесь картинка отображается, и это происходит в главной очереди. */
if (image!= nil){
/* Здесь создается вид с изображением. */
UIImageView *imageView = [[UIImageView alloc]
initWithFrame: self.view.bounds];
/* Задаем характеристики изображения. */
[imageView setImage: image];
/* Убеждаемся, что изображение масштабировано правильно. */
[imageView setContentMode: UIViewContentModeScaleAspectFit];
/* Добавляем изображение к виду данного контроллера вида. */
[self.view addSubview: imageView];
} else {
NSLog(@"Image isn't downloaded. Nothing to display.");
}
});
});
}
Как показано на рис. 7.2, мы успешно загрузили изображение, а также создали вид изображения, в котором картинка будет представлена пользователю в графическом интерфейсе.
Рис. 7.2. Загрузка изображения и демонстрация его пользователю, применяется GCD
Приведем другой пример. Допустим, у нас есть массив из 10 000 случайных чисел, которые сохранены в файле на диске. Мы хотим загрузить этот файл в память и отсортировать числа в порядке возрастания (то есть сделать так, чтобы список начинался с наименьшего числа). Потом мы хотим отобразить полученный список для пользователя. Инструмент управления, который будет применяться при этой операции, определяется тем, для какой системы вы пишете программу. В случае с iOS идеальным выходом было бы использовать экземпляр UITableView, а при работе с Mac OS X — экземпляр NSTableView. Поскольку массива у нас еще нет, начнем с его создания, потом загрузим этот массив, а потом отобразим.
Вот два метода, которые помогут нам найти место на диске устройства, где мы собираемся сохранить массив из 10 000 случайных чисел:
— (NSString *) fileLocation{
/* Получаем каталог (-и) документа. */
NSArray *folders =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
/* Мы что-нибудь нашли? */
if ([folders count] == 0){
return nil;
}
/* Получаем первый каталог. */
NSString *documentsFolder = [folders objectAtIndex:0];
/* Прикрепляем имя файла к концу пути документа. */
return [documentsFolder
stringByAppendingPathComponent:@"list.txt"];
}
— (BOOL) hasFileAlreadyBeenCreated{
BOOL result = NO;
NSFileManager *fileManager = [[NSFileManager alloc] init];
if ([fileManager fileExistsAtPath: [self fileLocation]]){
result = YES;
}
return result;
}
А вот теперь очень важный нюанс. Мы хотим сохранить на диске массив из 10 000 случайных чисел, если, и только если мы не создавали такой массив на диске раньше. В противном случае мы сразу загрузим массив с диска. Если же прежде мы не создавали этот массив на диске, то сначала создадим его, а потом перейдем к загрузке массива с диска. В итоге, если считывание массива с диска пройдет успешно, мы отсортируем этот массив в порядке возрастания и, наконец, отобразим результаты для пользователя в графическом интерфейсе. Реализацию отображения результатов пользователю оставляю вам для самостоятельной работы.
— (void) viewDidAppear:(BOOL)paramAnimated{
[super viewDidAppear: paramAnimated];
dispatch_queue_t concurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/* Если мы еще не отсортировали массив из 10 000 случайных чисел
на диске ранее, сгенерируем эти числа сейчас, а потом сохраним
их на диск в массиве. */
dispatch_async(concurrentQueue, ^{
NSUInteger numberOfValuesRequired = 10000;
if ([self hasFileAlreadyBeenCreated] == NO){
dispatch_sync(concurrentQueue, ^{
NSMutableArray *arrayOfRandomNumbers =
[[NSMutableArray alloc] initWithCapacity: numberOfValuesRequired];
NSUInteger counter = 0;
for (counter = 0;
counter < numberOfValuesRequired;
counter++){
unsigned int randomNumber =
arc4random() % ((unsigned int)RAND_MAX + 1);
[arrayOfRandomNumbers addObject:
[NSNumber numberWithUnsignedInt: randomNumber]];
}
/* Теперь записываем массив на диск. */
[arrayOfRandomNumbers writeToFile: [self fileLocation]
atomically: YES];
});
}
__block NSMutableArray *randomNumbers = nil;
/* Считываем числа с диска и сортируем их в порядке возрастания. */
dispatch_sync(concurrentQueue, ^{
/* Если файл на данный момент уже создан, занимаемся его считыванием. */
if ([self hasFileAlreadyBeenCreated]){
randomNumbers = [[NSMutableArray alloc]
initWithContentsOfFile: [self fileLocation]];
/* Теперь сортируем числа. */
[randomNumbers sortUsingComparator:
^NSComparisonResult(id obj1, id obj2) {
- QT 4: программирование GUI на С++ - Жасмин Бланшет - Программирование
- Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен - Программирование
- C# для профессионалов. Том II - Симон Робинсон - Программирование
- Стандарты программирования на С++. 101 правило и рекомендация - Герб Саттер - Программирование
- Программирование игр и головоломок - Жак Арсак - Программирование
- Генерация высококачественного кода для программ, написанных на СИ - Филипп Хислей - Программирование
- Программирование на Python с нуля - Максим Кононенко - Программирование
- C# 4.0: полное руководство - Герберт Шилдт - Программирование
- Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT. Часть 2 - Александр Фролов - Программирование
- От «Энигмы» до ChatGPT - Рустам Агамалиев - Программирование / Экономика