Используя Grand Central Dispatch, как я могу проверить, есть ли уже запущенный блок? - PullRequest
2 голосов
/ 14 июля 2011

Я использую GCD для фоновой загрузки из Интернета. Это прекрасно работает, за исключением небольшого недостатка. В моем приложении у меня есть 3 вкладки, и при нажатии на любую вкладку GCD начинает выполнять фоновую загрузку для соответствующей вкладки. Если пользователь решает перейти от первой вкладки ко второй вкладке (когда GCD начал загружать данные для первой вкладки), а затем снова возвращается к первой вкладке. GCD запустит другой фоновый поток (хотя первый фоновый поток еще не закончил загрузку данных).

Так есть ли способ проверить, работает ли фоновый поток в данный момент? Чтобы он не запускал несколько фоновых потоков, если пользователь решил бы переключать вкладки назад и вперед очень быстро (по некоторым причинам).

Ответы [ 2 ]

10 голосов
/ 14 июля 2011

Если вы хотите предотвратить одновременную работу двух блоков одного типа, вы можете использовать диспетчерский семафор.Если для семафора установлено значение 1, вы можете проверить семафор перед тем, как выстрелить из блока, и поручиться, если что-то еще работает.В конце блока вы даете сигнал семафору разрешить отправку других блоков.

Я делаю это в одном из моих приложений, чтобы предотвратить добавление более одного блока рендеринга кадров OpenGL ES в очередь водин раз (предотвращение накопления блоков в очереди, если на рендеринг кадра требуется больше 1/60 секунды).Я описываю это в своем ответе здесь , используя следующий код:

if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0)
{
    return;
}

dispatch_async(openGLESContextQueue, ^{

    [EAGLContext setCurrentContext:context];

    // Render here

    dispatch_semaphore_signal(frameRenderingSemaphore);
});

где frameRenderingSemaphore создан ранее следующим образом:

frameRenderingSemaphore = dispatch_semaphore_create(1);

Есливы создаете подобный семафор для операций загрузки каждой вкладки, вы можете проверить, чтобы убедиться, что более одной загрузки не ставится в очередь одновременно для этой вкладки.

0 голосов
/ 14 июля 2011

Вам нужен простой логический флаг, чтобы избежать повторного запуска задачи, пока она не будет завершена (вообще не включает GDC).Что-то вроде (псевдокод, не проверен, отказ от ответственности и т. Д.):

- (void)something_you_run_in_your_view_did_appear
{
    synchronize(self) {
        if (self.doing_task)
            return;
        self.doing_task = YES;
    }
    start_your_task_here
}

- (void)something_you_run_when_the_task_finishes
{
    synchronize(self) {
        self.doing_task = NO;
    }
}

Этот псевдокод будет работать для таких вещей, как асинхронное NSURLConnection.Я все еще не исследовал GDC, кому-то еще нужно будет адаптировать его к GDC (вы сами?).

Обратите внимание, что в этом примере я использую свойство, а не простой доступ к переменной.Это позволяет вам реализовывать более интересные вещи в установщике, такие как активация индикатора активности, отключение ввода пользовательского интерфейса и т. Д. И это также работает с подклассами, выполняющими свою вещь , когда состояние переменной изменяется в родительском классе..

...