停止并重新启动计时器

2024-04-17

我想停止这个计时器,然后从停止的地方重新启动它。

secondsTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(addSeconds), userInfo: nil, repeats: true)

下面,建议我不要在计时器处理程序中增加计时器。为什么不?

例如,使用GCD定时器:

func countSeconds() {

    secondsTimer = DispatchSource.makeTimerSource(queue: .main)
    secondsTimer?.schedule(deadline: .now(), repeating: 1.0)

    secondsTimer?.setEventHandler { [weak self] in

        self?.addSeconds()
    }
}

@objc func addSeconds() {
    seconds += 1                         
}

func startGame() {  
    secondsTimer?.resume()
}

我们不暂停/恢复Timer实例。我们阻止他们invalidate() https://developer.apple.com/documentation/foundation/timer/1415405-invalidate。当你想重新启动它时,只需创建新的计时器即可。

请参阅the Timer文档 https://developer.apple.com/documentation/foundation/timer,也可以直接在 Xcode 中使用。


请注意,您可以suspend https://developer.apple.com/documentation/dispatch/dispatchobject/1452801-suspend and resume https://developer.apple.com/documentation/dispatch/dispatchsourceprotocol/1781015-resumeGCD定时器,DispatchSourceTimer https://developer.apple.com/documentation/dispatch/dispatchsourcetimer.

var timer: DispatchSourceTimer?  // note, unlike `Timer`, we have to maintain strong reference to GCD timer sources

func createTimer() {
    timer = DispatchSource.makeTimerSource(queue: .main)
    timer?.schedule(deadline: .now(), repeating: 1.0)

    timer?.setEventHandler { [weak self] in      // assuming you're referencing `self` in here, use `weak` to avoid strong reference cycles
        // do something
    }

    // note, timer is not yet started; you have to call `timer?.resume()`
}

func startTimer() {
    timer?.resume()
}

func pauseTiemr() {
    timer?.suspend()
}

func stopTimer() {
    timer?.cancel()
    timer = nil
}

请注意,我并不是建议如果您愿意suspend and resume你应该使用GCDDispatchSourceTimer。呼唤invalidate并重新创造Timeras need 很简单,所以就这么做吧。我只是为了完整起见才提供此 GCD 信息。


顺便说一句,作为一般原则,永远不要“增加”计时器处理程序中的某些计数器。这是一个常见的错误。计时器不能保证每次都会触发或精确度准确。始终在开始时保存一些参考时间,然后在事件处理程序中计算当前时间和开始时间之间的差异。例如,扩展我的 GCD 计时器示例:

func createTimer() {
    timer = DispatchSource.makeTimerSource(queue: .main)
    timer?.schedule(deadline: .now(), repeating: 0.1)

    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .positional
    formatter.allowedUnits = [.hour, .minute, .second, .nanosecond]
    formatter.zeroFormattingBehavior = .pad

    timer?.setEventHandler { [weak self] in
        guard let start = self?.start else { return }
        let elapsed = (self?.totalElapsed ?? 0) + CACurrentMediaTime() - start
        self?.label.text = formatter.string(from: elapsed)
    }
}

var start: CFTimeInterval?         // if nil, timer not running
var totalElapsed: CFTimeInterval?

@objc func didTapButton(_ button: UIButton) {
    if start == nil {
        startTimer()
    } else {
        pauseTimer()
    }
}

private func startTimer() {
    start = CACurrentMediaTime()
    timer?.resume()
}

private func pauseTimer() {
    timer?.suspend()
    totalElapsed = (totalElapsed ?? 0) + (CACurrentMediaTime() - start!)
    start = nil
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

停止并重新启动计时器 的相关文章

随机推荐