Strange delay on NSTimer
I am having the following code in viewDidLoad method. All it does is updating a label every second. However when I run this code it shows the dummy text, waits a bit then it shows 8 sec instead of 9 then 8..
So it seems like it is skipping 9, is it possible to fix this? Should I have rounded the decimals when I calculate the time left?
Thank you for your time!
//Just dummy text
self.lblTime.text = @"Tid: 0h 0min 10sec";
NSDate *expireDate = [[NSDate alloc] initWithTimeInterval:10 sinceDate:[NSDate date]];
self.expires = expireDate;
[expireDate release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimerDisplay) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:UITrackingRunLoopMode];
In the updateTimerDisplay I have:
//Gets the time right now
NSDate *now = [NSDate date];
//Stores the difference in seconds between when the test was started and now.
NSTimeInterval interval = [self.expires timeIntervalSinceDate:now];
//Gets the number of hours
NSInteger hours = interval / 3600;
interval = (int)interval % 3600;
//Gets the number of seconds
NSInteger minutes = inter开发者_开发问答val / 60;
interval = (int)interval % 60;
NSInteger seconds = interval;
//Updates the label
self.lblTime.text = [NSString stringWithFormat:@"Time: %dh %dmin %dsec", hours, minutes, seconds];
NSTimer
is not guaranteed to fire exactly at the correct interval. The only thing you can be sure of is that the timer does not fire too early (assuming your device's clock runs at an accurate speed), but it is very possible that it fires too late.
In your case, even if the timer fires only a little too late, you will get a wrong result because you are not rounding your seconds
value, you just truncate it. You should consider rounding seconds
and/or having the timer fire more frequently (e.g. every 0.2 or 0.1 seconds).
Firstly, I'd recommend using [NSDate dateWithTimeIntervalSinceNow:10]
instead of [[NSDate alloc] initWithTimeInterval:10 sinceDate:[NSDate date]]
and [self.expires timeIntervalSinceNow]
instead of [self.expires timeIntervalSinceDate:[NSDate date]]
. These are more succinct.
Also remember that since self.expires
is an earlier date than now
in your second set of code, interval
will be negative, because the interval since now
is really the interval since self.expires
. Your code doesn't appear to take this fact into account.
Finally, If you set expires
to be 10 seconds into the future, and then get your timer to fire in a second, you may well have missed your 9 second mark. This is because all timers are inherently not 100% accurate, and so slightly more than 1 second may have elapsed. Say 1.01 seconds has elapsed, then that leaves 10 - 1.01 = 8.99 seconds remaining, which using integer math will be truncated to 8 seconds remaining. This seems to me to cause of your error. I'd generally recommend firing your timer more frequently that every second (every tenth of a second or so) to avoid these problems.
If you're interested, this is an example of temporal aliasing.
精彩评论