Как сделать секундомер таймер - PullRequest
0 голосов
/ 17 февраля 2020

По какой-то причине секундомер выглядит нормально, но по сравнению с реальной сделкой он идет слишком быстро. Я не понимаю, что я должен делать. Это timeInterval, что я должен изменить? Я бы хотел, чтобы он показывал миллисекунды, секунды и минуты, но все, что я пробую, только усугубляет ситуацию. Спасибо

import UIKit
class ViewController: UIViewController {

    // Outlets
    @IBOutlet weak var minutes: UILabel!
    @IBOutlet weak var seconds: UILabel!
    @IBOutlet weak var milliSecondsLabel: UILabel!

    @IBOutlet weak var resetButton: UIButton!
    @IBOutlet weak var startButton: UIButton!
    @IBOutlet weak var pauseButton: UIButton!

    // Variables
    var timer = Timer()
    var time: Int = 0
    var running: Bool = false

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        roundButtons()

    }

    @IBAction func resetTimer(_ sender: Any) {
        timer.invalidate()
        time = 0
        updateUI()
        running = false
    }

    @IBAction func startTimer(_ sender: Any) {
        if running {
            return
        } else {
            timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(timerDidEnd), userInfo: nil, repeats: true)
            running = true
        }

    }

    @IBAction func pauseTimer(_ sender: Any) {
        timer.invalidate()
        running = false
    }


    func roundButtons() {
        resetButton.layer.cornerRadius = resetButton.frame.height / 2
        startButton.layer.cornerRadius = startButton.frame.height / 2
        pauseButton.layer.cornerRadius = pauseButton.frame.height / 2
    }

    @objc func timerDidEnd() {
        time += 1
        updateUI()
    }

    func updateUI() {

        var min: Int
        var sec: Int
        var mil: Int

        min = time / (60*60)
        sec = (time/60)%60
        mil = time & 60

        minutes.text = String(min)
        seconds.text = String(sec)
        milliSecondsLabel.text = String(mil)
    }
}

1 Ответ

0 голосов
/ 17 февраля 2020

Я бы предложил две вещи:

  1. Не пытайтесь сосчитать прошедшее время самостоятельно. Захватите время начала и вычислите истекшее время из этого. Вы можете использовать Date метод timeIntervalSince, или, поскольку это не гарантирует возврата монотонно увеличивающихся значений, используйте CACurrentMediaTime, как показано ниже.

  2. Вместо того, чтобы иметь таймер с произвольными 100 обновлениями в секунду, вместо этого используйте CADisplayLink, который оптимально рассчитан для скорости обновления экрана устройства sh.

Например:

class ViewController: UIViewController {

    // Outlets
    @IBOutlet weak var minutesLabel: UILabel!
    @IBOutlet weak var secondsLabel: UILabel!
    @IBOutlet weak var milliSecondsLabel: UILabel!

    @IBOutlet weak var resetButton: UIButton!
    @IBOutlet weak var startButton: UIButton!
    @IBOutlet weak var pauseButton: UIButton!

    // Variables
    private weak var displayLink: CADisplayLink?
    private var startTime: CFTimeInterval?
    private var elapsed: CFTimeInterval = 0
    private var priorElapsed: CFTimeInterval = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        setFonts()
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        roundButtons()
    }

    @IBAction func resetTimer(_ sender: Any) {
        stopDisplayLink()
        elapsed = 0
        priorElapsed = 0
        updateUI()
    }

    @IBAction func startTimer(_ sender: Any) {
        if displayLink == nil {
            startDisplayLink()
        }
    }

    @IBAction func pauseTimer(_ sender: Any) {
        priorElapsed += elapsed
        elapsed = 0
        displayLink?.invalidate()
    }
}

private extension ViewController {
    func startDisplayLink() {
        startTime = CACurrentMediaTime()
        let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
        displayLink.add(to: .main, forMode: .common)
        self.displayLink = displayLink
    }

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

    @objc func handleDisplayLink(_ displayLink: CADisplayLink) {
        guard let startTime = startTime else { return }
        elapsed = CACurrentMediaTime() - startTime
        updateUI()
    }

    func updateUI() {
        let totalElapsed = elapsed + priorElapsed

        let hundredths = Int((totalElapsed * 100).rounded())
        let (minutes, hundredthsOfSeconds) = hundredths.quotientAndRemainder(dividingBy: 60 * 100)
        let (seconds, milliseconds) = hundredthsOfSeconds.quotientAndRemainder(dividingBy: 100)

        minutesLabel.text = String(minutes)
        secondsLabel.text = String(format: "%02d", seconds)
        milliSecondsLabel.text = String(format: "%02d", milliseconds)
    }

    func roundButtons() {
        resetButton.layer.cornerRadius = resetButton.bounds.height / 2
        startButton.layer.cornerRadius = startButton.bounds.height / 2
        pauseButton.layer.cornerRadius = pauseButton.bounds.height / 2
    }

    func setFonts() {
        minutesLabel.font = UIFont.monospacedDigitSystemFont(ofSize: minutesLabel.font.pointSize, weight: .regular)
        secondsLabel.font = UIFont.monospacedDigitSystemFont(ofSize: secondsLabel.font.pointSize, weight: .regular)
        milliSecondsLabel.font = UIFont.monospacedDigitSystemFont(ofSize: milliSecondsLabel.font.pointSize, weight: .regular)
    }
}

Это дает:

enter image description here


Полностью не связано, но все зависит по размеру просмотров (например, скругление углов) действительно принадлежит viewDidLayoutSubviews, а не viewDidLoad.

...