Как я могу периодически запускать блок кода в фоновом режиме с помощью GCD? Я пытаюсь написать игровой движок с несколькими подсистемами, такими как рендеринг, физика, игровая логика и так далее. Некоторые задачи должны управляться событиями, но некоторые (например, физическую систему) следует периодически вызывать в фоновом режиме с постоянным временем (например, через 1/100 сек). Я создал блок кода, но как я могу запускать этот блок периодически в фоновом режиме? Правильный ли инструмент GCD?
Как я могу периодически запускать блок кода в фоновом режиме с помощью GCD?
Ответ 1
То, что вы хотите, это источник отправки GCD. Пример кода см. В Создание примера таймера.
Ответ 2
Как отмечает @matt в комментариях, для этого вы можете использовать источники отправки таймера. Посмотрите его ответ на правильный подход.
Для потомков, здесь мой оригинальный ответ с некоторыми альтернативами:
-
В обратном вызове рендеринга (скажем, используя CADisplayLink), запустите задание GCD, которое вычисляет физику для этого ( или следующий?). Если вам нужно сделать несколько обновлений для каждого кадра рендеринга, просто запустите этот цикл работы пару раз.
-
У вас есть физический поток, который спит сам, пока ему не потребуется некоторое вычисление. Если у вас есть отдельный поток для этого, NSTimer может иметь достаточное разрешение, чтобы разбудить поток до 100 Гц. (В основном потоке это не сработало, потому что другие источники ввода в runloop не позволят ему быстро запускать его.) Если NSTimer не работает, просто вычислите, сколько времени осталось до следующего физического обновления, которое вам нужно, и спящий поток (через, например,
[NSThread sleepForTimeInterval:]
) -
Имейте блок, который использует
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
В 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)