2009-06-23 56 views
13

Estoy intentando crear un temporizador de cuenta atrás que lleva la cuenta atrás, un IBOutlet conectado a un campo de texto, desde 60 segundos a 0. No estoy seguro detemporizador de cuenta regresiva

A. Cómo limitar las repeticiones a 60 y

B. ¿Cómo disminuir la cuenta atrás en advanceTimer:

- (IBAction)startCountdown:(id)sender 
{ 
    NSTimer *countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self  selector:@selector(advanceTimer:) userInfo:nil repeats:YES]; 
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
    [runLoop addTimer:countdownTimer forMode:NSDefaultRunLoopMode]; 
} 

- (void)advanceTimer:(NSTimer *)timer 
{ 
    [countdown setIntegerValue:59]; 
} 

Respuesta

19

Estás en el camino correcto hasta el momento.

Siguiendo con el código que ya tiene, aquí es cómo advanceTimer método debe buscar para hacer que funcione:

- (void)advanceTimer:(NSTimer *)timer 
{ 
    [countdown setIntegerValue:([countdown integerValue] - 1)]; 
    if ([countdown integerValue] == 0) 
    { 
     // code to stop the timer 
    } 
} 

edición: Para hacer que todo sea más orientado a objetos, y para evitar la conversión a partir de cadenas a números y volver cada vez, me gustaría en vez de hacer algo como esto:

// Controller.h: 
@interface Controller 
{ 
    int counter; 
    IBOutlet NSTextField * countdownField; 
} 
@property (assign) int counter; 
- (IBAction)startCountdown:(id)sender; 
@end 

// Controller.m: 
@implementation Controller 

- (IBAction)startCountdown:(id)sender 
{ 
    counter = 60; 

    NSTimer *countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1 
             target:self 
             selector:@selector(advanceTimer:) 
             userInfo:nil 
             repeats:YES]; 
} 

- (void)advanceTimer:(NSTimer *)timer 
{ 
    [self setCounter:(counter -1)]; 
    [countdownField setIntegerValue:counter]; 
    if (counter <= 0) { [timer invalidate]; } 
} 

@end 

Y, si se puede hacer uso de fijaciones, simplemente podría obligar del campo de texto intValue a la propiedad de la counterController. Esto le permitiría eliminar el IBOutlet en la interfaz de clase, y la línea setIntegerValue: en advanceTimer.

actualización: Se ha eliminado el código que agrega el temporizador al ciclo de ejecución dos veces. Gracias a Nikolai Ruhe y nschmidt por notar ese error.

actualización: Se utilizó el método setIntegerValue para simplificar el código, de acuerdo con nschmidt.

edición: del error tipográfico en la definición de (void) advanceTimer: temporizador (NSTimer *) ... causado molesto 'selector no reconocido enviado a la instancia' excepción

+0

El temporizador de cuenta regresiva se agrega dos veces al ciclo de ejecución, lo que es incorrecto. –

+0

@Nikolai Ruhe: Gracias por señalar eso. He eliminado el código incorrecto de mis ejemplos. –

+0

Supongo que setIntegerValue es más eficiente que [NSString stringWithFormat:], así que no habría hecho esta "optimización". Especialmente porque no ayuda a la claridad del código. – nschmidt

6

Puede añadir una variable de instancia _timerValue int para mantener la valor del temporizador y luego haga lo siguiente. También tenga en cuenta que el NSTimer que está creando ya está programado en el ciclo de ejecución actual.

- (IBAction)startCountdown:(id)sender 
{ 
    _timerValue = 60; 
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(advanceTimer:) userInfo:nil repeats:NO]; 
} 

- (void)advanceTimer:(NSTimer *)timer 
{ 
    --_timerValue; 
    if(self.timerValue != 0) 
     [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(advanceTimer:) userInfo:nil repeats:NO]; 

    [countdown setIntegerValue:_timerValue]; 
} 
Cuestiones relacionadas