简体   繁体   English

如何使NSTimer更准确?

[英]How to make NSTimer more accurate?

In my app, I put a label on the view controller and I want that label to display a number which is incremented by 1 every millisecond. 在我的应用程序中,我在视图控制器上放置了一个标签,并且希望该标签显示一个数字,该数字每毫秒递增1。 (I know I can just update it every second by 1000, but I want it to look smooth) (我知道我可以每秒更新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()
}

The code all looks very sensible to me, but when I run the app, I see that the number is increasing by about 50 every second, not 1000 every second. 这些代码对我来说似乎都非常明智,但是当我运行该应用程序时,我发现该数字每秒增加约50,而不是每秒增加1000。 That error is far from acceptable! 这个错误是远远不能接受的!

Surprisingly, when I lock the screen for a few seconds and unlock it again, the number suddenly increases by a few thousands! 令人惊讶的是,当我锁定屏幕几秒钟并再次解锁时,数字突然增加了几千!

I think this is because I am updating the UI when the timer fires so it requires more time. 我认为这是因为计时器触发时我正在更新UI,所以需要更多时间。 But how can I fix this? 但是我该如何解决呢?

Your question is asking how to make NSTimer more accurate and I have some bad news: you can't. 您的问题是询问如何使NSTimer更准确,但我有一个坏消息:您不能。 A reasonable expectation of NSTimer is that it can be called ~30 times per second and, if you're lucky, up to ~60 times per second. NSTimer的合理预期是每秒可以调用30次,如果幸运的话,每秒可以调用60次。 And that's okay. 没关系。

Thinking of this from a practical point of view: the display can only be updated up to 60 times per second, so there is no need to give user feedback more often than that. 从实用的角度考虑:每秒最多只能更新60次显示,因此不需要给用户更多的反馈。

If you're trying to max out the hardware and rely on it firing as fast as possible, then you're going to have issues on older and slower hardware where it might only fire ~20 times per second. 如果您试图最大限度地利用硬件,并依靠它尽可能快地触发,那么您将在较旧和较慢的硬件上遇到问题,它们可能每秒只能触发约20次。 Relying on the time interval of NSTimer will get you in trouble quickly. 依靠NSTimer的时间间隔会很快给您带来麻烦。

Since you're looking for milliseconds, you can set a start time and every time your function is called look at the number of milliseconds since your start time and that's the number of transpired milliseconds. 由于您要查找毫秒,因此可以设置开始时间,每次调用函数时,请查看自开始时间以来的毫秒数,即所发生的毫秒数。

Your current method does everything Apple's documentation says it should: number is just the count of times that method has been called (not the number of transpired milliseconds). 您当前的方法可以执行Apple文档所说明的所有操作: number只是该方法被调用的次数(不是传输的毫秒数)。

Building on @Fennelouski's answer, what I suggest is you swap to a CADisplayLink which is pretty much made for this kind of task. 在@Fennelouski的答案的基础上,我建议您交换到CADisplayLink ,这几乎是用于此类任务的。 It will call your method once every screen update (or once every 2nd or 3rd, or whatever you make the frameInterval property). 它将在每次屏幕更新时(或每第2或第3次,或任何使frameInterval属性的情况)一次调用您的方法。 it also has a timestamp variable that you can use to calculate how much time has passed and update your label accordingly 它还具有一个timestamp变量,您可以使用该变量来计算经过了多少时间并相应地更新标签

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM