NSTimer的准确性

时间:2013-07-01 21:55:15

标签: objective-c nstimer

我正在尝试使用NSTimer创建一个Stop-watch样式计时器,每0.1秒递增一次,但有时它似乎运行得太快..

我就是这样做的:

Timer =[NSTimer scheduledTimerWithTimeInterval: 0.1 target:self selector:@selector(updateTimeLabel) userInfo:nil repeats: YES];

然后:

-(void)updateTimeLabel
{
    maxTime=maxTime+0.1;
    timerLabel.text =[NSString stringWithFormat:@"%.1f Seconds",maxTime];
}

这将在Label中显示计时器的值,稍后我可以将maxTime用作Timer停止的时间...

问题在于它运行非常不准确。

有没有一种方法可以确保NSTimer严格每0.1秒准确发射一次?我知道NSTimer不准确,我要求进行调整以使其准确。

感谢

4 个答案:

答案 0 :(得分:9)

根据NSTimer文档,它并不准确。

  

由于典型的运行循环管理各种输入源,因此定时器的时间间隔的有效分辨率限制在50-100毫秒的量级。如果在长时间标注期间或在运行循环处于不监视计时器的模式下发生计时器的触发时间,则计时器在下次运行循环检查计时器之前不会触发。因此,计时器可能发射的实际时间可能是计划发射时间之后的一段很长时间。

您可能希望使用GCD中的dispatch_after函数,official documentation为此目的建议(创建计时器)。

  

如果您想在指定的时间间隔后执行一次阻止,可以使用dispatch_afterdispatch_after_f功能。


顺便说一句,我同意Caleb的回答。如果你不像现在这样积累错误,你可能会解决你的问题。 如果您使用-timeIntervalSince:方法存储开始日期并在每次迭代时重新计算时间,那么无论计时器精度如何,您都将获得准确的UI更新。

答案 1 :(得分:5)

这是一个你可以用来做你想做的课:

@interface StopWatch()
@property ( nonatomic, strong ) NSTimer * displayTimer ;
@property ( nonatomic ) CFAbsoluteTime startTime ;
@end

@implementation StopWatch

-(void)dealloc
{
    [ self.displayTimer invalidate ] ;
}

-(void)startTimer
{
    self.startTime = CFAbsoluteTimeGetCurrent() ;
    self.displayTimer = [ NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector( timerFired: ) userInfo:nil repeats:YES ] ;
}

-(void)stopTimer
{
    [ self.displayTimer invalidate ] ;
    self.displayTimer = nil ;

    CFAbsoluteTime elapsedTime = CFAbsoluteTimeGetCurrent() - self.startTime ;
    [ self updateDisplay:elapsedTime ] ;
}

-(void)timerFired:(NSTimer*)timer
{
    CFAbsoluteTime elapsedTime = CFAbsoluteTimeGetCurrent() - self.startTime ;
    [ self updateDisplay:elapsedTime ] ;
}

-(void)updateDisplay:(CFAbsoluteTime)elapsedTime
{
    // update your label here
}

@end

关键点是:

  1. 通过在秒表启动时将系统时间保存为变量来确定您的时间。
  2. 当秒表停止时,通过从当前时间减去秒表开始时间来计算经过时间
  3. 使用计时器更新您的显示器。如果您的计时器是否准确无关紧要。如果您尝试保证显示更新至少每0.1秒,您可以尝试将定时器间隔设置为最小更新时间的1/2(0.05s)。

答案 2 :(得分:4)

maxTime=maxTime+0.1;

这是错误的方法。您不希望使用计时器来累积经过的时间,因为您将累积错误。使用计时器定期触发使用NSDate计算已用时间的方法,然后更新显示。因此,请更改代码以执行某些操作:

maxTime = [[NSDate date] timeIntervalSince:startDate];

答案 3 :(得分:2)

NSTimer不保证准确,但在实践中通常是(如果你在主线程上没有做任何其他事情......)。但是,更新显示器是完全合理的...只是不要使用回调计算您的计时器。在启动计时器时保存当前时间,并在每次计时器触发时从现在开始到开始时间之间取得差异。然后,NSTimer的触发准确程度并不重要,它只影响屏幕显示每秒更新的次数。