Книга: iOS. Приемы программирования
Обсуждение
Обсуждение
GCD позволяет создавать группы. Пользуясь группами, можно поместить несколько задач в одном месте, выполнить их все, а по завершении работы получить об этом уведомление от GCD. Такая технология имеет большое прикладное значение. Допустим, например, что у вас есть приложение с пользовательским интерфейсом и вы хотите перезагрузить его компоненты в этом пользовательском интерфейсе. В пользовательском интерфейсе у вас имеется табличный вид, прокручиваемый вид и вид с изображением. Вы хотите перезагрузить содержимое этих компонентов с помощью следующих методов:
— (void) reloadTableView{
/* Здесь перезагружается табличный вид. */
NSLog(@"%s", __FUNCTION__);
}
— (void) reloadScrollView{
/* Здесь выполняется работа. */
NSLog(@"%s", __FUNCTION__);
}
— (void) reloadImageView{
/* Здесь перезагружается вид с изображением. */
NSLog(@"%s", __FUNCTION__);
}
На данный момент эти методы пусты, но вы можете позже поместить в них важный код, связанный с пользовательским интерфейсом. Сейчас мы собираемся вызвать эти три метода один за другим и узнать, когда GCD закончит вызывать эти методы, в результате чего мы отобразим соответствующее сообщение для пользователя. Для этого нам придется воспользоваться группой. При работе с группами в GCD необходимо иметь представление о трех функциях:
• dispatch_group_create — создает описатель группы;
• dispatch_group_async — отправляет блок кода в группу для выполнения. Необходимо указать диспетчерскую очередь, в которой должен выполняться этот блок кода, а также группу, к которой этот блок кода относится;
• dispatch_group_notify — позволяет отправить блоковый объект, который необходимо выполнить после того, как все задачи, направленные в группу для выполнения, закончат свою работу. Эта функция также позволяет указывать диспетчерскую очередь, в которой должен выполняться данный блоковый объект.
Рассмотрим пример. Как объяснялось ранее, в этом примере мы собираемся активизировать методы reloadTableView, reloadScrollView и reloadImageView один за другим, а потом отобразить для пользователя сообщение о том, что задача выполнена. Для достижения этой цели применим мощные групповые функции, присущие GCD:
— (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
dispatch_group_t taskGroup = dispatch_group_create();
dispatch_queue_t mainQueue = dispatch_get_main_queue();
/* Перезагружаем табличный вид в главной очереди. */
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadTableView];
});
/* Перезагружаем прокручиваемый вид в главной очереди. */
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadScrollView];
});
/* Перезагружаем вид с изображением в главной очереди. */
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadImageView];
});
/* Когда все это будет сделано, диспетчеризуем следующий блок. */
dispatch_group_notify(taskGroup, mainQueue, ^{
/* Здесь происходит обработка. */
[[[UIAlertView alloc] initWithTitle:@"Finished"
message:@"All tasks are finished"
delegate: nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil, nil] show];
});
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Кроме работы с функцией dispatch_group_async, можно также направлять асинхронные функции на языке C, используя функцию dispatch_group_async_f.
GCDAppDelegate — это просто имя класса, из которого взят пример. Данное имя класса мы будем использовать для приведения типа контекстного объекта так, чтобы компилятор понимал наши команды.
Вот так:
void reloadAllComponents(void *context){
AppDelegate *self = (__bridge AppDelegate *)context;
[self reloadTableView];
[self reloadScrollView];
[self reloadImageView];
}
— (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
dispatch_group_t taskGroup = dispatch_group_create();
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_group_async_f(taskGroup,
mainQueue,
(__bridge void *)self,
reloadAllComponents);
/* Когда все это будет сделано, диспетчеризуем следующий блок. */
dispatch_group_notify(taskGroup, mainQueue, ^{
/* Здесь происходит обработка. */
[[[UIAlertView alloc] initWithTitle:@"Finished"
message:@"All tasks are finished"
delegate: nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil, nil] show];
});
self.window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Поскольку функция dispatch_group_async_f принимает функцию на языке C как блок кода для исполнения, у функции C должна быть ссылка на self, чтобы она могла активизировать методы экземпляра актуального объекта, где реализована функция C. Вот почему self передается как указатель контекста в функции dispatch_group_async_f. Подробнее о контекстах и функциях C рассказано в разделе 7.4.
После того как все поставленные задачи будут завершены, пользователь увидит примерно такую картинку, как на рис. 7.3.
Рис. 7.3. Управление группой задач в GCD