一尘不染

使用Swift将实时秒表计时器格式化为百分之一

swift

我有一个使用NSTimer的应用程序,该应用程序在百秒(0.01秒)的更新间隔下以String格式显示正在运行的秒表,格式为00:00.00(mm:ss.SS)。(基本上克隆iOS内置秒表以集成到实时体育计时数学问题中,将来可能需要毫秒级精度)

我使用(滥用?)NSTimer强制更新UILabel。如果用户按下开始,这是用于开始重复该功能的NSTimer代码:

displayOnlyTimer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("display"), userInfo: nil, repeats: true)

这是上面的NSTimer执行的函数:

func display() {
    let currentTime = CACurrentMediaTime() - timerStarted + elapsedTime

    if currentTime < 60 {
        timeDisplay.text = String(format: "%.2f", currentTime)
    }else if currentTime < 3600 {
        var minutes = String(format: "%00d", Int(currentTime/60))
        var seconds = String(format: "%05.2f", currentTime % 60)
        timeDisplay.text =  minutes + ":" + seconds
    }else {
        var hours = String(format: "%00d", Int(currentTime/3600))
        var minutes = String(format: "%02d", (Int(currentTime/60)-(Int(currentTime/3600)*60)))
        var seconds = String(format: "%05.2f", currentTime % 60)
        timeDisplay.text =  hours + ":" + minutes + ":" + seconds
    }
}

至少有2个显示链接同时运行。一旦所有其他要素都发挥作用,此方法是否会太低效?

然后,当用户按下停止/暂停/重置时,无需使用NSTimer即可更新显示。我没有发现任何直接翻译成Swift的东西。我相当确定我正在使用一种效率低下的方法来强制在UIView中快速更新文本UILabel。

更多详细信息:我正在为运行的计时器格式(mm:ss.SS)编写较少混乱的代码。完成后,我将再次更新。

更新:感谢Rob和jtbandes回答了我两个问题(格式化方法和显示更新方法)。用CADisplayLink()替换NSTimer(参见上文)很容易:

displayLink = CADisplayLink(target: self, selector: Selector("display"))
        displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes)

然后替换代码中的所有实例

displayOnlyTimer.invalidate()

displayLink.paused = true

(这将暂停显示链接的更新)


阅读 369

收藏
2020-07-07

共1个答案

一尘不染

为了快速更新UI,您应该使用CADisplayLink。任何比显示刷新速率快的操作都将浪费处理能力,因为它实际上无法显示。它还提供了timestamp上一帧的图像,因此您可以尝试预测下一帧的时间。

您正在计算CACurrentMediaTime() - timerStarted + elapsedTime多次。我建议只做一次并将其保存在本地变量中。

考虑使用NSDateComponentsFormatter。尝试重用格式化程序的一个实例,而不是每次都创建一个新的(通常是最昂贵的部分)。总体而言,您可以执行的字符串操作越少越好。

您可以在显示方法的开始和结束处检查CACurrentMediaTime,以了解需要花费多长时间。理想情况下,应
比少16.6ms。注意Xcode调试导航器中的CPU使用率(和一般功耗)。

2020-07-07