Как я могу периодически запускать блок кода в фоновом режиме, используя GCD? - PullRequest
12 голосов
/ 18 декабря 2011

Как я могу периодически запускать блок кода в фоновом режиме, используя GCD?Я пытаюсь написать игровой движок с несколькими подсистемами, такими как рендеринг, физика, игровая логика и так далее.Некоторые задачи должны определяться событиями, но некоторые (например, физическая система) должны периодически вызываться в фоновом режиме с постоянным временем (например, через 1/100 секунды).Я создал блок кода, но как я могу периодически запускать этот блок в фоновом режиме?Правильный ли здесь инструмент GCD?

Ответы [ 3 ]

10 голосов
/ 18 декабря 2011

То, что вы хотите, это источник отправки GCD.Для примера кода см. Пример создания таймера .

6 голосов
/ 18 декабря 2011

Как отмечает @matt в комментариях, вы можете использовать источники таймера для этого. См. Его ответ для правильного подхода там.

Для потомков, вот мой оригинальный ответ с некоторыми альтернативами:

  1. При обратном вызове рендеринга (скажем, с использованием CADisplayLink ) запустите GCD-задание, которое вычисляет физику для этого (или следующего?) Кадра. Если вам нужно сделать более одного обновления для каждого фрейма рендеринга, просто сделайте этот цикл работы пару раз.

  2. Имейте физический поток, который спит до тех пор, пока в следующий раз ему не понадобятся вычисления. Если у вас есть отдельный поток для этого, NSTimer может иметь достаточное разрешение для пробуждения вашего потока на частоте 100 Гц. (В главном потоке это не сработает, потому что другие источники входных данных в цикле выполнения не позволят ему так быстро запускаться.) Если NSTimer не работает, просто вычислите, сколько времени осталось до следующего необходимого вам обновления физики, и спите вашу ветку (например, [NSThread sleepForTimeInterval:])

  3. Есть блок, который использует dispatch_after.

Примерно так:

dispatch_time_t next = dispatch_time(DISPATCH_TIME_NOW, 0);
block = ^{
    next = dispatch_time(next, 10000000L); // increment by 10 ms
    // do physics here
    dispatch_after(next, queue, block);
}

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

3 голосов
/ 16 марта 2015

В Swift вы можете создать таймер используя GCD:

func CreateTimerDispatchSource(interval: UInt64, leeway: UInt64, queue: dispatch_queue_t, block: dispatch_block_t) -> dispatch_source_t {
    let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
    dispatch_source_set_timer(timer, dispatch_walltime(nil, 0), interval, leeway)
    dispatch_source_set_event_handler(timer, block)
    return timer;
}

var timer = CreateTimerDispatchSource(5*NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
  // do some serious stuff
}

Таймер запуска или возобновления:

dispatch_resume(timer)

Таймер приостановки:

dispatch_suspend(timer)
...