2011-12-18 4 views
12

¿Cómo puedo ejecutar el bloqueo de código en el fondo periódicamente utilizando GCD? Estoy tratando de escribir un motor de juego con varios subsistemas, como renderizado, física, lógica de juegos, etc. Algunas tareas deben ser impulsadas por eventos, pero algunas (como el sistema de física) se deben llamar periódicamente en el fondo con un tiempo constante (por ejemplo, después de 1/100 segundos). Creé un bloque de código, pero ¿cómo puedo ejecutar este bloque periódicamente en segundo plano? ¿La herramienta correcta de GCD aquí?¿Cómo puedo ejecutar el bloqueo de código en el fondo periódicamente usando GCD?

Respuesta

6

Como notas de @matt en los comentarios, puede usar las fuentes de envío de temporizador para esto. Vea su respuesta para el enfoque correcto allí.

Para la posteridad, aquí está mi respuesta original con algunas alternativas:

  1. En su devolución de llamada render (por ejemplo, usando CADisplayLink), disparar un trabajo GCD que calcula la física de este (o el siguiente?) marco. Si necesita hacer más de una actualización por fotograma de renderizado, solo tenga ese bucle de trabajo un par de veces.

  2. Tienen un hilo de física que duerme hasta que el próximo necesita hacer algunos cálculos. Si tiene un hilo separado para esto, NSTimer puede tener suficiente resolución para activar su subproceso a 100 Hz. (En el hilo principal, esto no funcionaría porque otras fuentes de entrada en el runloop evitarán que se active tan rápido). Si NSTimer no funciona, simplemente calcule cuánto tiempo falta para la próxima actualización física que necesita y duerma su hilo (por ejemplo, [NSThread sleepForTimeInterval:])

  3. Tienen un bloque que usa dispatch_after.

Algo como esto:

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); 
} 

puede que tenga que ser un poco más inteligentes acerca de pérdida de fotogramas, (es decir, detectar si su próxima vez que está en el pasado antes de llamar dispatch_after ella, etc.)

+0

Hola, gracias por la respuesta. Mi principal objetivo es desacoplar el subsistema de física del renderizado, por lo que creo que la segunda respuesta es más adecuada para mí, sin embargo, aún me pregunto si hay alguna solución con bloques y GCD. – asdf

+0

OK. He agregado una tercera opción. –

+1

"Las fuentes de envío del temporizador generan eventos a intervalos regulares basados ​​en el tiempo. Puede usar temporizadores para iniciar tareas específicas que deben realizarse regularmente. Por ejemplo, los juegos y otras aplicaciones intensivas en gráficos pueden usar temporizadores para iniciar actualizaciones de pantalla o animación. " Si ese no es el GCD que admite tareas periódicas directamente, y exactamente en el contexto sobre el que el OP pregunta, ¿qué es? – matt

3

En Swift puede crear temporizador utilizando 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 
} 

de inicio o reanudar temporizador:

dispatch_resume(timer) 

Suspender temporizador:

dispatch_suspend(timer) 
Cuestiones relacionadas