2012-07-19 28 views
6

Tengo un UILabel que quiero mostrar la hora actual (HH: mm) (al mismo tiempo que en la barra de estado).UILabel con la hora actual

¿Cómo actualizo la etiqueta para cambiar a la nueva hora? Si programo un NSTimer con un intervalo de 60 segundos, entonces la etiqueta podría estar fuera de tiempo en hasta un minuto, si el temporizador se dispara justo antes de que cambie el minuto de la hora del sistema.

¿Sería correcto establecer el intervalo del temporizador en 1 segundo o utilizará más recursos de los necesarios? ¿O hay otra forma de asegurarse de que la etiqueta se mantenga sincronizada con el reloj de la barra de estado (preferiblemente exactamente, pero la vía de 1 segundo de Lee está bien)?

Respuesta

5

el envío es su amigo:

void runBlockEveryMinute(dispatch_block_t block) 
{ 
    block(); // initial block call 

    // get the current time 
    struct timespec startPopTime; 
    gettimeofday((struct timeval *) &startPopTime, NULL); 

    // trim the time 
    startPopTime.tv_sec -= (startPopTime.tv_sec % 60); 
    startPopTime.tv_sec += 60; 

    dispatch_time_t time = dispatch_walltime(&startPopTime, 0); 

    __block dispatch_block_t afterBlock = ^(void) { 
     block(); 

     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60), dispatch_get_main_queue(), afterBlock); 
    }; 

    dispatch_after(time, dispatch_get_main_queue(), afterBlock); // start the 'timer' going 
} 

Esto sincronizará hasta el nanosegundo y sólo llamar cuando cambia la hora. Creo que esta es la solución óptima para su situación.

+0

Muy bien, arregló el código, funciona como un encanto ahora! –

+0

Gran respuesta. Pero el código puede causar un ciclo de retención en ARC. He editado la respuesta para solucionar ese problema. – Peng90

0

Creo que correría un NSTimer con un retraso de 1 segundo en una secuencia de fondo, haga que el método se ejecute controle la hora actual (HH: mm) a la hora actual que se muestra en la etiqueta. Si coincide con tirarlo, si es nuevo, actualice la etiqueta.

Si le preocupa el rendimiento, después de regresar la primera vez, descubra cuántos segundos quedan del minuto siguiente y haga que funcione el temporizador durante ese tiempo. Luego, después de la primera actualización, ejecute el temporizador en intervalos de 60 segundos.

0

un segundo es la respuesta correcta.

+0

en la programación, menos es más. – Eric

1

Estaría bien para establecer el intervalo del temporizador a 1 segundo, o habrá que utilizar más recursos de los necesarios?

Depende de lo que estés haciendo. Si está calculando el primer millón de dígitos de pi, o representando varios cientos de objetos 3-D, necesitará cada ciclo de procesador que pueda ahorrar. Si la CPU está inactiva la mayor parte del tiempo, también puede usar esos ciclos para que su interfaz se vea bien.

+0

Cosas como la duración de la batería también deberían ser una preocupación. – jadengeller

0

Tal vez pueda configurar dos temporizadores. El primero (disparado una vez) se usa para sincronizar el segundo temporizador con un intervalo de 60 segundos, que lo dispara cuando la hora del sistema llega a HH: 00;

1
//Create a timer... 
timer = [NSTimer scheduledTimerWithTimeInterval:0.25 
               target:self 
               selector:@selector(tick:) 
               userInfo:NULL 
               repeats:YES]; 
//Function to update time 
- (void)tick:(NSTimer*)t 
{ 
    NSDate *now = [NSDate date]; 
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
    [dateFormatter setDateFormat:@"HH:mm:ss"]; 
    NSString *timeString = [dateFormatter stringFromDate:now]; 
    [uilabel setText:timeString]; 
} 

su temporizador siempre será "retrasado" por algún tiempo, ya que no hay funciones de "delegado" para llamar para realizar dicha función.

Me quedaría con el temporizador, pero el envío como Richard J. Ross III mencionado es válido también.

0

Actualizaciones sincronizadas de segunda precisión sin gettimeofday o bloques. Puntero débil y dispatch_async para evitar el ciclo de retención.

- (void)updateTimeLabel 
{ 
    if (!timeFormatter) { 
     timeFormatter = [NSDateFormatter new]; 
     timeFormatter.dateStyle = NSDateFormatterNoStyle; 
     timeFormatter.timeStyle = NSDateFormatterShortStyle; 
    } 
    NSDate *currentTime = [NSDate date]; 
    NSTimeInterval delay = [[currentTime nextMinute] timeIntervalSinceDate:currentTime]; 

    timeLabel.text = [timeFormatter stringFromDate:currentTime]; 

    __weak id weakSelf = self; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [weakSelf performSelector:@selector(updateTimeLabel) withObject:nil afterDelay:delay]; 
    }); 
} 

Obtén el siguiente minuto con 0 segundos.

@implementation NSDate (Utils) 
- (NSDate *)nextMinute { 
    NSCalendar *calendar = [NSCalendar currentCalendar]; 

    NSDateComponents *comps = [calendar components:(NSCalendarUnit) NSUIntegerMax fromDate:self]; 
    comps.minute += 1; 
    comps.second = 0; 

    return [calendar dateFromComponents:comps]; 
} 
@end 

Creo que hay un ciclo de retener con bloqueo en la respuesta de Richard (que puede ser fijado con __weak + dispatch_async)