如何使 NSTimer 更准确?

How to make NSTimer more accurate?

在我的应用程序中,我在视图控制器上放置了一个标签,我希望该标签显示一个每毫秒递增 1 的数字。 (我知道我可以每秒更新 1000,但我希望它看起来平滑)

@IBOutlet var label: UILabel!
var number = 0
var timer: NSTimer!

override func viewDidLoad() {
    super.viewDidLoad()
    timer = NSTimer.scheduledTimerWithTimeInterval(0.001, target: self, selector: Selector("addNumber"), userInfo: nil, repeats: true)
}

func addNumber () {
    number++
    label.text = number.description
}

override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    timer?.invalidate()
}

代码对我来说看起来都很合理,但是当我 运行 应用程序时,我看到数字每秒增加大约 50,而不是每秒 1000。这个错误是无法接受的!

没想到,当我锁屏几秒再解锁的时候,数字突然增加了几千!

我认为这是因为我在计时器触发时更新 UI,因此需要更多时间。但是我该如何解决这个问题?

你的问题是询问如何使 NSTimer 更准确,我有一些坏消息:你不能。 NSTimer 的合理预期是它每秒可以调用约 30 次,如果幸运的话,每秒可以调用约 60 次。没关系。

从实际的角度考虑:显示最多只能每秒更新 60 次,因此没有必要更频繁地向用户提供反馈。

如果您试图最大限度地利用硬件并依靠它尽可能快地启动,那么您将在较旧和较慢的硬件上遇到问题,它可能每秒只能启动约 20 次。 依靠 NSTimer 的时间间隔会让你很快陷入困境。

由于您要查找的是毫秒数,因此您可以设置一个开始时间,每次调用您的函数时,查看自开始时间以来的毫秒数,这就是经过的毫秒数。

您当前的方法会执行 Apple 文档中规定的所有操作:number 只是该方法被调用的次数(不是经过的毫秒数)。

基于@Fennelouski 的回答,我建议您换成 CADisplayLink,它非常适合此类任务。它会在每次屏幕更新时调用您的方法(或每 2 次或 3 次,或任何您设置的 frameInterval 属性)。它还有一个 timestamp 变量,你可以用它来计算已经过去了多少时间并相应地更新你的标签