В прошлой статье мы познакомились с очередями выполнения задач и с некоторыми функциями, которые позволяют запускать задачи на выполнение. В этой статье мы рассмотрим еще несколько функций, которые запускают задачи на выполнение.
dispatch_once
Функция dispatch_once используется, когда конкретную задачу нужно выполнить только один раз за все время жизни приложения. Это может быть полезным, например, при инициализации синглтона, как это советовали тут. Такие конструкции, я думаю, вы видели не раз:
static BOOL isSomethingInited = NO; if ( isSomethingInited ) { // инициализируем что-нибудь // и выставляем флаг isSomethingInited = YES; }
С помощью GCD и функции dispatch_once этот код можно заменить вот таким:
static dispatch_once_t task; dispatch_once(&task, ^{ // код });
dispatch_after
Вы можете использовать эту функцию, когда хотите отложить выполнение задачи на некоторое время. Рассмотрим пример:
double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // код });
Обратите внимание на то, что нет гарантий, что код запуститься сразу по истечении времени. Когда пройдет время, задача станет в очередь на выполнение, а начнет она выполняться или нет — зависит уже от нагруженности самой очереди. Но, обычно, задачи стартуют во время или с небольшой погрешностью.
Время, когда запускать задачу на выполнение представлено структурой dispatch_time_t, которая создается функцией dispatch_time. Она определяет сколько времени (второй аргумент), прошло от конкретного времени (первый аргумент). В данном случае мы используем текуще время DISPATCH_TIME_NOW и отсчитываем от него две секунды. Время отсчета задается в нано секундах. Если мы хотим использовать время в секундах, то нам нужно умножать количество секунд на NSEC_PER_SEC (наносекунд в секунде). Если мы хотим отсчитать милисикунды, можно использовать NSEC_PER_MSEC).
dispatch_apply
Эта функция используется для запуска задачи на выполнение несколько раз. Функция возвращает управление когда все запущенные задачы будут закончены.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(10, queue, ^(size_t index) { // блок выполнится 10 раз // в блок передается номер запуска });
dispatch_apply распаралеливает выполнение задач. Например, если запустить вот такой код:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(10, queue, ^(size_t index) { NSLog(@"%@ , %zu",[NSDate date], index); });
В консоли мы можем увидеть вот такое:
2012-06-13 19:08:31 +0000 , 0 2012-06-13 19:08:31 +0000 , 2 2012-06-13 19:08:31 +0000 , 3 2012-06-13 19:08:31 +0000 , 4 2012-06-13 19:08:31 +0000 , 5 2012-06-13 19:08:31 +0000 , 6 2012-06-13 19:08:31 +0000 , 7 2012-06-13 19:08:31 +0000 , 8 2012-06-13 19:08:31 +0000 , 9 2012-06-13 19:08:31 +0000 , 1
Это говорит о том, что задачи действительно распарателиваются.
На этом все. В следующих статьях мы рассмотрим методы управления очередями и механизм семафоров в GCD. Спасибо за внимание!