开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜