Ios 秒表未同步

Ios 秒表未同步,ios,swift,timer,Ios,Swift,Timer,抱歉,如果这是一个新手问题,我对iOS&Swift非常陌生。我对计时器间隔有一个问题:我设置了0.01时间间隔,但它与计时器标签不对应,因为0.01在一毫秒内对应,但不显示它。所以基本上计时器是倾斜的 timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(updateStopwatch) , userInfo: nil, repeats: true) @IBAction func s

抱歉,如果这是一个新手问题,我对iOS&Swift非常陌生。我对计时器间隔有一个问题:我设置了0.01时间间隔,但它与计时器标签不对应,因为0.01在一毫秒内对应,但不显示它。所以基本上计时器是倾斜的

timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(updateStopwatch) , userInfo: nil, repeats: true)

@IBAction func startStopButton(_ sender: Any) {
    buttonTapped()
}


func updateStopwatch() {
    milliseconds += 1
    if milliseconds == 100 {
        seconds += 1
        milliseconds = 0
    }
    if seconds == 60 {
        minutes += 1
        seconds = 0
    }
    let millisecondsString = milliseconds > 9 ?"\(milliseconds)" : "0\(milliseconds)"
    let secondsString = seconds > 9 ?"\(seconds)" : "0\(seconds)"
    let minutesString = minutes > 9 ?"\(minutes)" : "0\(minutes)"
    stopWatchString = "\(minutesString):\(secondsString).\(millisecondsString)"
    labelTimer.text = stopWatchString
}

func buttonTapped() {
    if isTimerRunning {
        isTimerRunning = !isTimerRunning
        timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(updateStopwatch) , userInfo: nil, repeats: true)
        startStopButton.setTitle("Stop", for: .normal)
    }else{
        isTimerRunning = !isTimerRunning
        timer.invalidate()
        startStopButton.setTitle("Start", for: .normal)
    }
}

scheduledTimer的时间延迟只是近似值,由于iOS开销,它可能与请求的延迟相差很多毫秒。重复计时器的计时效果更差,因为任何延迟抖动错误都会累积。因此,不要使用计时器来计时更长的事件

CADisplayLink是一种更可靠的计时器,因为它与60 Hz的显示器刷新同步(例如,这是除最新的iPad Pros之外的设备上任何UILabel可以更改的最大速率)。试图更快地更新时间显示是没有用的(最新的iPad Pros除外)

也不要使用日期方法来计时,因为当设备连接到网络时,它们不能保证是单调的(因为NTP可以在计时活动的中间改变时钟时间)。


您应该对照一个内置计时器(如马赫时间)检查任何已用时间测量UI。mach_absolute_time()保证是单调的,不受NTP或其他网络活动的影响。

设备具有最大屏幕更新速率(大多数为60 fps),因此没有必要比这更快。要获得最大屏幕刷新率,请使用定时器,而不是
定时器,该定时器与屏幕刷新完美协调(不仅在频率上,而且在屏幕刷新周期内的计时上)

另外,也不要试图通过添加一些值来跟踪经过的时间(因为不能保证它将以所需的频率被调用)。相反,在启动计时器/显示链接之前,请保存启动时间,然后在调用计时器/显示链接时,以所需格式显示经过的时间

例如:

var startTime: CFTimeInterval!
weak var displayLink: CADisplayLink?

func startDisplayLink() {
    self.displayLink?.invalidate()  // stop prior display link, if any
    startTime = CACurrentMediaTime()
    let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
    displayLink.add(to: .current, forMode: .commonModes)
    self.displayLink = displayLink
}

func handleDisplayLink(_ displayLink: CADisplayLink) {
    let elapsed = CACurrentMediaTime() - startTime
    let minutes = Int(elapsed / 60)
    let seconds = elapsed - CFTimeInterval(minutes) * 60
    let string = String(format: "%02d:%05.2f", minutes, seconds)

    labelTimer.text = string
}

func stopDisplayLink() {
    displayLink?.invalidate()
}

注意,使用
mach_时间
,如hotpaw2正确建议,但会为您进行秒的转换。

.01这不是1毫秒,您永远不应该使用计时器来计算时间。只需存储开始日期并获取自该日期起的时间间隔。100毫秒不是1秒。0.1秒。请记住,“毫”是1/1000,而不是1/100。NSDate不应用于计时。它甚至可能不是单调的(据报道,它甚至可以在NTP时钟调整过程中倒退)。你不想让秒表报负时间@JimboPower您建议,
CADisplayLink
“听起来很复杂”。实际上,它并不比计时器复杂,但使用基于计时器的方法解决了许多问题。