NSTimer不够精确

时间:2016-04-01 12:56:28

标签: ios swift nsdate nstimer

我正在设置定时器,以便在每个完成后执行代码。然而,似乎NSTimer的时机并不完全准确,过了一段时间,计时器似乎有点太早了。

我已设置以下内容来测试偏差。

(开始按钮在故事板中完成并链接到。)

import UIKit

class ViewController: UIViewController {

  @IBOutlet weak var startButton: UIButton!

  //var mainTimer: NSTimer!
  var counter: NSTimeInterval = 0.0

  @IBAction func startButtonPressed(sender: AnyObject) {
    startMainTimer()
    startTimers()
  }

  func startMainTimer() {
    let mainTimer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: #selector(ViewController.count), userInfo: nil, repeats: true)
    NSRunLoop.mainRunLoop().addTimer(mainTimer, forMode: NSRunLoopCommonModes)
  }

  func count() {
    counter += 0.01
  }

  func startTimers() {
    var lastTimeInterval: NSTimeInterval = 0.0

    for _ in 0..<50 {
      let timeInterval = lastTimeInterval + 1.0
      lastTimeInterval = timeInterval

      // Not setting up a repeating timer as intervals would be different in my original project where the deviation will be even worse.
      let timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: #selector(ViewController.printTime), userInfo: nil, repeats: false)
      NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
    }
  }

  func printTime() {
    print(counter)
  }
}

在此之后,计时器将在十分之一秒或更早的时间。 我应该使用NSDate来获得更好的时机,还是会过于复杂?以上如何看待NSDate?

非常感谢任何帮助/指示!

1 个答案:

答案 0 :(得分:1)

它永远不会是完美的,但你可以通过在目标选择器的末尾安排下一个调用来阻止它复合。每次根据当前时间和您希望触发的时间计算新的间隔。

编辑:我从一个非常古老的项目中抓取了一些代码来提出这个想法(这就是它在Obj-C中的原因) - 你想要这样的东西但不完全是:

- (void)constantIntervalTimer {
   static const NSTimeInterval secondsBetweenMessageSend = 1.0;

   if ( !self.timerShouldStop ) {
      NSDate *startTime = [NSDate date];

      // your code here, it should take less than a
      // second to run or you need to increase the timer interval

      // figure out the right time to preserve the interval
      NSTimeInterval waitTime = secondsBetweenMessageSend -
           [[NSDate date] timeIntervalSinceDate:startTime];

      // in case your code runs in more than the interval,
      // we just call back immediately
      if (waitTime < 0.0) 
         waitTime = 0.0;

      [NSTimer scheduledTimerWithTimeInterval: waitTime
            target:self selector:@selector(constantIntervalTimer) 
            userInfo:nil repeats:NO];
    }
}

一旦调用此消息,它将每秒调用一次,直到您将名为timerShouldStop的属性设置为YES。您必须声明并定义此属性,并在init中将其设置为NO,以使此消息起作用。