在 Swift 中准确测量时间以进行跨设备比较

Measuring Time Accurately in Swift for Comparison Across Devices

我需要能够记录反应时间,从屏幕加载或问题标签刷新到用户点击数字按钮。我没有发现 Apple 提供的关于此的文档非常有帮助。 NSDate不够准确,至少要精确到毫秒。 mach_absolute_time似乎受到游戏设计师的青睐,因为它内部一致,但它不适用于此应用程序,因为我需要跨设备比较数据,并且mach_absolute_time是CPU依赖时间. This Apple Dev Q&A 建议使用 NanosecondsToAbsoluteDurationToAbsolute 但它在 obj-c 中,我找不到 swift 等效文档。

是否有 NanosecondsToAbsoluteDurationToAbsolute 的 swift 版本我只是找不到?有其他方法可以始终如一地做到这一点吗?

这是我要添加时间的代码:

class EmotionQuestionsViewController: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

//mark "startTime" when view loads
    }

    @IBOutlet var questionLabel: UILabel!
    var timeResultsStack = [String]()

    var questionsStack = ["HAPPY", "ANXIOUS"]
    var questionResultsStack = [String]()
    var questionStackArrayIndex = 1

    @IBAction func RecordValueFromNumericalScaleOneToSeven(sender: UIButton) {

//mark durration time as currentTime - startTime, append to timeResultsStack

        let value = sender.currentTitle!
        questionResultsStack.append(value)

        if questionResultsStack.count < questionsStack.count{
            self.questionLabel.text = "how \(questionsStack[questionStackArrayIndex]) are you right now?"

//mark startTime when label is changed

            self.questionStackArrayIndex++

        }
        else{
            self.performSegueWithIdentifier("showResults", sender: nil)

        }
    }

NSDate 与 iOS 和 Mac 设备上的实时时钟相关联,具有亚毫秒精度。

使用 NSDate 的 timeIntervalSinceReferenceDate 方法将 NSDate(或当前时间)转换为双精度值,即自 2001 年 1 月 1 日以来的秒数,包括小数秒。一旦你这样做了,你就可以自由地对你得到的双打进行数学计算。

您可以使用 NSTimeInterval 来测量时间(比计时器好得多)。您只需要存储两个日期(两个时间点)并减去 endTime - StartTime,如下所示:

import UIKit

class ViewController: UIViewController {

    var startTime: TimeInterval = 0
    var endTime: TimeInterval = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        startTime = Date().timeIntervalSinceReferenceDate
    }

    @IBAction func stopTimeAction(_ sender: Any) {
        endTime = Date().timeIntervalSinceReferenceDate
        print((endTime-startTime).time)
    }

}

extension TimeInterval {
    var time: String { .init(format: "%d:%02d:%02d.%03d", Int(self/3600),
                        Int((self/60).truncatingRemainder(dividingBy: 60)),
                        Int(truncatingRemainder(dividingBy: 60)),
                        Int((self*1000).truncatingRemainder(dividingBy: 1000))) }
}

如前所述,NSDate() 的精度可能足够好 为了你的目的。为了完整起见,mach_absolute_time() 来自所引用的 技术问答 QA1398 也适用于 Swift:

let t1 = mach_absolute_time()
// do something
let t2 = mach_absolute_time()

let elapsed = t2 - t1
var timeBaseInfo = mach_timebase_info_data_t()
mach_timebase_info(&timeBaseInfo)
let elapsedNano = elapsed * UInt64(timeBaseInfo.numer) / UInt64(timeBaseInfo.denom);
print(elapsedNano)

这种方法可能的优势:

  • 调用 mach_absolute_time() 似乎比调用快得多 NSDate().timeIntervalSinceReferenceDate,所以这个方法可能是 更适合测量极短的间隔。
  • 如果调整时钟,NSDate()的值会改变, mach_absolute_time()没有这个问题。