6

我正在尝试使用 NSTimer 创建一个秒表样式的计时器,该计时器每 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];
}

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

问题是它运行非常不准确。

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

谢谢

4

4 回答 4

9

根据NSTimer文档,这并不意味着准确。

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

您可能想要使用dispatch_afterGCD 中的函数,官方文档为此确切目的(创建计时器)建议了该函数。

如果要在指定的时间间隔后执行一次块,可以使用dispatch_afterordispatch_after_f函数。


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

于 2013-07-01T22:07:56.693 回答
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 秒更新一次,您可以尝试将计时器间隔设置为最小更新时间 (0.05 秒) 的 1/2。
于 2013-07-01T22:17:51.563 回答
4
maxTime=maxTime+0.1;

这是错误的方法。您不想使用计时器来累积经过的时间,因为您将随之累积错误。使用计时器周期性地触发一个使用 计算经过时间的方法NSDate,然后更新显示。所以,改变你的代码来做一些事情:

maxTime = [[NSDate date] timeIntervalSince:startDate];
于 2013-07-01T22:13:11.500 回答
2

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

于 2013-07-01T22:11:29.297 回答