I'm trying to create a countdown timer that takes countdown, an IBOutlet connected to a textfield, from 60 seconds down to 0. I'm not sure
A. How to limit the repeats to 60 and
B. How to decrement the countdown in 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];
}
You're on the right track so far.
Sticking with the code you already have, here is how advanceTimer
method should look to make it work:
- (void)advanceTimer:(NSTimer *)timer
{
[countdown setIntegerValue:([countdown integerValue] - 1)];
if ([countdown integerValue] == 0)
{
// code to stop the timer
}
}
edit: To make the whole thing more object-oriented, and to avoid converting from strings to numbers and back every time, I would instead do something like this:
// 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
And, if you can make use of bindings, you could simply bind the text field's intValue
to the counter
property of the Controller
. This would allow you to elminate the IBOutlet
in the class interface, and the setIntegerValue:
line in advanceTimer
.
update: Removed the code which adds the timer to the run loop twice. Thank you to Nikolai Ruhe and nschmidt for noticing that error.
update: Used the setIntegerValue
method to simplify the code, as per nschmidt.
edit: Typo in definition of (void)advanceTimer:(NSTimer *)timer ... caused annoying 'unrecognized selector sent to instance' exception
You can add a instance variable int _timerValue to hold the timer value and then do the following. Also note that the NSTimer you are creating is already scheduled on the current run loop.
- (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];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With