在 Swift 中准确测量时间以进行跨设备比较
Measuring Time Accurately in Swift for Comparison Across Devices
我需要能够记录反应时间,从屏幕加载或问题标签刷新到用户点击数字按钮。我没有发现 Apple 提供的关于此的文档非常有帮助。 NSDate
不够准确,至少要精确到毫秒。 mach_absolute_time
似乎受到游戏设计师的青睐,因为它内部一致,但它不适用于此应用程序,因为我需要跨设备比较数据,并且mach_absolute_time
是CPU依赖时间. This Apple Dev Q&A 建议使用 NanosecondsToAbsolute
和 DurationToAbsolute
但它在 obj-c 中,我找不到 swift 等效文档。
是否有 NanosecondsToAbsolute
和 DurationToAbsolute
的 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()
没有这个问题。
我需要能够记录反应时间,从屏幕加载或问题标签刷新到用户点击数字按钮。我没有发现 Apple 提供的关于此的文档非常有帮助。 NSDate
不够准确,至少要精确到毫秒。 mach_absolute_time
似乎受到游戏设计师的青睐,因为它内部一致,但它不适用于此应用程序,因为我需要跨设备比较数据,并且mach_absolute_time
是CPU依赖时间. This Apple Dev Q&A 建议使用 NanosecondsToAbsolute
和 DurationToAbsolute
但它在 obj-c 中,我找不到 swift 等效文档。
是否有 NanosecondsToAbsolute
和 DurationToAbsolute
的 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()
没有这个问题。