1

我一直在使用 NSTimers 来触发我的应用程序中对时间敏感的某些事件(基本上,当我告诉它们以第二个分辨率发生时必须发生)。但是,我一直遇到这种情况,有时,计时器之前会触发,所以如果我记录计时器触发的日期,它可能会说14:34:59而不是14:35:00. 这有点烦人。我在文档中搜索了解释并发现了这一点:

  • 由于典型的运行循环管理的各种输入源,计时器的时间间隔的有效分辨率被限制在 50-100 毫秒的数量级。

和这个:

  • 如果在长时间调用期间或运行循环处于不监视计时器的模式下发生计时器的触发时间,则计时器不会触发,直到下一次运行循环检查计时器。

所以计时器的分辨率为 100 毫秒,这可以解释为什么计时器之前触发,但前提是这有任何意义。之所以没有,是因为人们会认为 100ms 的差异是由延迟引起的,而不是相反。

那么,1:为什么计时器在其时间之前触发,以及2:我该如何避免这种情况?

编辑:

这就是我计算日期的方式:

  1. 我从一个 NSDate 对象开始([NSDate now] 或来自 NSDatePicker 的日期)
  2. 我使用 NSDateComponents添加到该日期x天数
  3. 我再次使用 NSDateComponents 设置了该日期的小时、数字和秒(但保留步骤 2 中的日/月/年)
  4. 我这样设置计时器:

    timer = [NSTimer timerWithTimeInterval: 10 目标:自我选择器:@selector(myMethod) userInfo: nil repeats: NO];

    [定时器setFireDate:fireDate];

    [[NSRunLoop currentRunLoop] addTimer: timer forMode: NSRunLoopCommonModes];

编辑2:

我还记录了时间间隔(而不是小时/分钟/秒),它总是x.0000,这意味着它正好在第二个开始,它应该是什么(不是之前,不是之后)。

4

1 回答 1

2

Chances are you are calculating the time interval (seconds) incorrectly. Note that this is an NSTimeInterval, which is defined as a double. Are you per chance rounding the time interval to the nearest second? In that case when rounding down the timer will fire too early.

Edit: There is indeed empirical evidence that NSTimer may fire early. My guess is that the accuracy mentioned in the documentation is not just + but +/- and the runloop does something along to the lines of if(fireDelta>-0.0xxx) then fireNow();.

So to work around that:

  • Always add a small delta to the firing time and hope the delta is enough (ugly and not guaranteed)

  • When the timer fires, do if(timer.fireDate.timeIntervalSinceNow>0.0) then and reschedule a timer with the same fireDate. Still ugly...

于 2013-05-10T15:03:57.297 回答