cocoa nsdate nstimer

cocoa - NSTimer no se dispara cuando se bloquea runloop



nsdate (2)

Estoy a punto de terminar mi aplicación y las pruebas beta detectaron un error en la parte del cronómetro ... El cronómetro utiliza un nstimer para contar y tiene una tabla para almacenar vueltas, pero cuando se desplaza la tabla de vueltas, el reloj se detiene o hace una pausa y no compensa el tiempo perdido.

Esto fue estancamiento fue eliminado mediante el uso de:

startingTime = [[NSDate date] timeIntervalSince1970];

para calcular el tiempo transcurrido.

pero todavía estoy usando el NSTimer para disparar cada 0.1 segundos y eso significa que el desplazamiento todavía detiene el cronómetro aunque el tiempo transcurrido se actualizará correctamente al final ... y al compararlo con el cronómetro de Apple me pregunto si eso el cronómetro tiene un hilo separado solo para el conteo del tiempo transcurrido. ¿Alguien sabe si así es como se hace?

Ahora, usando el tiempo desde que The Epoch está funcionando bien en un sentido, pero complica la cuestión de iniciar, detener y reiniciar el cronómetro

cuando se detiene el reloj, la hora se almacena y se usa para calcular un desplazamiento para cuando se reinicie el reloj, pero parece que se ha introducido algo de latencia y el tiempo avanza visiblemente cuando se reinicia el reloj.

Cualquier pensamiento hacia la causa raíz o una solución sería muy apreciado.


La respuesta de bbum proporciona una mejor manera de diseñar su aplicación, pero si desea que su temporizador se dispare independientemente de si el usuario está manipulando la UI o no, tendrá que agregarlo al modo de rastreo del runloop.

Suponiendo que está desarrollando para el iPhone, ese modo es UITrackingRunLoopMode . Si está desarrollando para Mac existe un nombre similar llamado NSEventTrackingRunLoopMode .

NSRunLoop *runloop = [NSRunLoop currentRunLoop]; NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(myTimerAction:) userInfo:nil repeats:YES]; [runloop addTimer:timer forMode:NSRunLoopCommonModes]; [runloop addTimer:timer forMode:UITrackingRunLoopMode];


Si el bucle de eventos no se está ejecutando, los temporizadores no se dispararán hasta que el bucle de eventos pueda volver a ejecutarse. Incluso si el bucle de evento no está bloqueado, no se garantiza que el temporizador se dispare exactamente a su intervalo configurado. Si sus tiempos se basan completamente en disparos de temporizadores, la cantidad de errores crecerá con el tiempo.

Debe realizar un seguimiento de la duración por separado del disparo de los temporizadores. Cada vez que se dispara un temporizador, vuelva a calcular su duración y vuelva a mostrarlo.

Para un tipo de configuración de inicio / pausa / reinicio / detención, generalmente desea:

  • tomar el tiempo al inicio (ya sea como una instancia NSDate o como un valor NSTimeInterval)

  • al detenerse o detenerse, tome el tiempo en pausa / parada. Resta la hora de inicio a partir de este momento y tienes la duración del intervalo

  • al reiniciar, tome el tiempo al reiniciar, pero también mantenga alrededor de la duración ya transcurrida

  • al detener / detener, tome el tiempo en pausa / detener y agregue la duración ya transcurrida

En general, hacer todo esto con los valores de NSTimeInterval, que son solo dobles, es más fácil. Sin embargo, si necesita realizar un seguimiento del momento real en el momento en que ocurrieron los eventos, use las instancias NSDate en su lugar.