问题
Currently I am developing a game which needs a stop watch say 1 minute,when user taps the play button it enters the game screen,I want the to run the stop watch count down of 1 minute 01:00,00:59,00:58 etc. For that reason I searched and found NSTimer would be the ideal choice to implement a stop watch.Hence I took a label,created an instance of NSTimer,assigned time interval and started decrementing the value in timer label,i.e.:
-(void)viewDidAppear:(BOOL)animated
{
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(viewWillAppear:) userInfo:nil repeats:YES];
[super viewDidAppear:YES];
}
-(void)viewWillAppear:(BOOL)animated
{
static int currentTime = 60;
int newTime = currentTime--;
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:@"%02d:%02d", minutesRemaining, secondsRemaining];
if ([self.timerLabel.text isEqualToString:@"00:00"])
{
[stopWatchTimer invalidate];
}
[super viewWillAppear:YES];
}
The problem here is the timer starts running 01:00,00:59,00:58 and goes on,say at 53rd second,I navigated to another view and came back,it is running from 00:53,00:52 and so on,but I want it to run from 01:00 and for that I implemented invalidating NSTimer in viewDidDisappear i.e.
-(void)viewDidDisappear:(BOOL)animated
{
if ([stopWatchTimer isValid])
{
[stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
[super viewDidDisappear:YES];
}
Still the same issue exists!
Done lots of Research on the issue and found no answer useful and working.
Can some one please guide me,any help is appreciated.
Thanks every one in advance :)
回答1:
You are use the selector viewWillAppear
for the timer. viewWillAppear
is a method on a viewController that gets called when the view appears on screen, you should not call it yourself. Instead, create your own method that decrements the timer:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];
currentTime = 60; // This could be an instance variable
self.timerLabel.text = @"01:00";
}
-(void)updateTime {
int newTime = currentTime--;
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:@"%02d:%02d", minutesRemaining, secondsRemaining];
if ([self.timerLabel.text isEqualToString:@"00:00"])
{
[self.stopWatchTimer invalidate];
}
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if ([self.stopWatchTimer isValid])
{
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
}
With this technique the timer is responsible for calling every second, but you will probably have timing issues after some seconds. To have a more accurate timing, you should store the time that you started the countdown and then on every updateTime
call, compare the current time with the stored started time.
Add to your interface:
@property (nonatomic) NSTimeInterval startTime;
then in the implementation:
-(void)viewDidAppear:(BOOL)animated
{
self.startTime = [NSDate timeIntervalSinceReferenceDate];
self.duration = 60; // How long the countdown should be
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(updateTime)
userInfo:nil
repeats:YES];
self.timerLabel.text = @"01:00"; // Make sure this represents the countdown time
}
-(void)updateTime {
int newTime = self.duration - (round([NSDate timeIntervalSinceReferenceDate] - self.startTime));
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:@"%02d:%02d", minutesRemaining, secondsRemaining];
if (newTime < 1)
{
[self.stopWatchTimer invalidate];
/* Do more stuff here */
}
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if ([self.stopWatchTimer isValid])
{
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
}
Some extra (unrelated) comments on the code:
when implementing viewDidDisappear:
pass the animated
parameter to the call to super:
[super viewDidDisappear:animated];
when implementing viewDidAppear:
pass the animated
parameter to the call to super, also, make sure you call super first this in the method, before doing anything else
来源:https://stackoverflow.com/questions/16689433/reset-nstimer-after-navigating-to-another-view