2009-06-23 8 views
13

Próbuję utworzyć czasomierza, że ​​trwa odliczanie, IBOutlet podłączony do pola tekstowego, od 60 sekund do 0. Nie jestem pewienOdliczanie

A. Jak ograniczyć liczbę powtórzeń do 60 i

B. Jak zmniejszyć odliczanie w 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]; 
} 

Odpowiedz

19

jesteś na dobrej drodze do tej pory.

Kłucie z kodem już masz, oto jak advanceTimer metoda powinna wyglądać, aby to działało:

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

edit: Aby cała sprawa bardziej zorientowanym obiektowo i aby uniknąć konwersja z ciągów liczb i do tyłu za każdym razem, chciałbym zamiast zrobić coś takiego:

// 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 

I, jeśli można skorzystać z wiązaniami, można po prostu powiązać pole tekstowe na intValue do majątku Controllercounter. Umożliwi to wyeliminowanie interfejsu IBOutlet w interfejsie klasy i linii setIntegerValue: w advanceTimer.

Aktualizacja: aktualizacja: Usunięto kod, który dwukrotnie dodaje timer do pętli uruchamiania. Dziękuję Nikolai Ruhe i nschmidtowi za zauważenie tego błędu.

aktualizacja: Zastosowano metodę setIntegerValue, aby uprościć kod, zgodnie z nschmidt.

edit: Typo w definicji (void) advanceTimer: (*) NSTimer czasomierz ... spowodowane irytujące 'nierozpoznany selektor wysyłane do instancji' wyjątku

+0

CountdownTimer jest dodawany dwukrotnie do pętli uruchamiania, co jest błędem. –

+0

@Nikolai Ruhe: Dziękuję za wskazanie tego. Usunąłem niepoprawny kod z moich przykładów. –

+0

Domyślam się, że setIntegerValue jest bardziej wydajne niż [NSString stringWithFormat:], więc nie zrobiłbym tej "optymalizacji". Zwłaszcza, że ​​nie pomaga to w jasności kodu. – nschmidt

6

Możesz dodać instancja zmiennej int _timerValue trzymanie Wartość zegara, a następnie wykonaj następujące czynności. Zauważ też, że NSTimer, który tworzysz, jest już zaplanowany w bieżącej pętli uruchamiania.

- (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]; 
}