2011-06-03 13 views
29

Uso un NSTimer que se dispara cada segundo y actualiza una etiqueta que muestra el tiempo restante hasta un evento.¿Cómo actualizar una etiqueta periódicamente en iOS (cada segundo)?

Hasta ahora estoy bien. El problema es que mientras estoy desplazando el TableView, mi etiqueta no se actualiza, porque MainThread está bloqueado por el evento touch/scroll.

Pensé en crear un segundo hilo para el temporizador, pero no pude actualizar la etiqueta de un hilo de fondo de todos modos. Tuve que ponerla en cola con performSelector ... en MainThread, donde quedaría como antes.

¿Hay alguna forma de actualizar la etiqueta mientras se desplaza?

Respuesta

44

El problema es que una scheduledTimer no se llamará mientras que el hilo principal es el seguimiento de toques. Necesitas programar el temporizador en el ciclo de ejecución principal.

Así que en lugar de hacer

[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLabel:) userInfo:nil repeats:YES]; 

uso

NSTimer* timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(updateLabel:) userInfo:nil repeats:YES]; 
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 
+0

Pensé que scheduledTimerWithTimeInterval lo agrega al bucle de ejecución actual que ES el mainRunLoop porque mi aplicación es de un solo hilo. –

+0

NSRunLoopCommonModes hará que su temporizador siga recibiendo llamadas incluso mientras la vista de tabla sigue sus toques. – DHamrick

+0

@Alexander: lo agrega al modo de ciclo de ejecución * predeterminado *, no a todos los modos considerados * comunes * a los modos de ciclo de ejecución. Durante el seguimiento táctil, el ciclo de ejecución se ejecuta en un modo diferente al predeterminado, por lo que no se verifica su temporizador. –

0

probar esto:

self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateClock) userInfo:nil repeats:YES]; 
    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; 
-3

Usted podría también utilizar GCD. Así que corre

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); 
dispatch_async(queue, ^{ 
    [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateLabel:) userInfo:nil repeats:YES]; 
}); 

y ahora en su método de updateLabel

- (void) updateLabel:(id) sender { 
    NSString *text = @"some text"; 
    dispatch_sync(dispatch_get_main_queue(), ^{ 
     label.text = text; 
    }); 
} 

Esto actualizará la etiqueta en el hilo principal.

+0

Esa es una receta para el desastre. El temporizador se registra con el runloop de cualquier hilo aleatorio (y probablemente temporal) que la cola concurrente de alta prioridad decida usar, lo que significa que tal vez nunca tenga la oportunidad de disparar. Si desea usar un retraso con GCD, use 'dispatch_after'. En este caso, lo configurará para enviar el bloque después de 1 segundo a la cola principal. –

+0

hrmm ... sí, creo que tiene sentido. En ese caso, ¿cómo se vería el código de envío? – brandontreb

+0

Ver por ejemplo https://gist.github.com/1006912. Los comentarios son un mal lugar para escribir el código. –

Cuestiones relacionadas