Остановка таймера на определенное количество времени в Swift - PullRequest
0 голосов
/ 26 июня 2018

Я пытаюсь создать секундомер, который, например, будет отсчитывать до 3,0 секунд, останавливаться, а затем позволит мне переопределить вид приложения новым фоном / меткой.Моя проблема в том, что я не могу найти способ, чтобы таймер мог остановиться и сделать паузу самостоятельно на 3 секунды - всякий раз, когда я писал оператор, он просто продолжал считать и ничего не делал.Куда бы я положил утверждение в этом коде, и как бы я написал его?

import UIKit

class ViewController: UIViewController {
    var time = 0.0
    var timer = Timer()

    @IBOutlet weak var lbl: UILabel!

    @IBAction func start(_ sender: UIButton)
    {
        timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: false)
    }

    @IBAction func pause(_ sender: UIButton)
    {
        timer.invalidate()
    }

    @IBAction func reset(_ sender: UIButton)
    {
        timer.invalidate()
        time = 0.0
        lbl.text = ("0")
    }

    @objc func action()
    {
        time += 0.1
        lbl.text = String(time)
    }
}

1 Ответ

0 голосов
/ 26 июня 2018

Начните с развязки ваших ожиданий.

«Часы» - это контейнер для периода времени, с которого они были начаты до настоящего времени.Кроме того, он может быть «перезапущен», поэтому может потребоваться узнать, как долго длился каждый предыдущий цикл выполнения, а затем он будет добавлен к общей продолжительности «часов»

. Timer - это простоспособ запустить некоторый код на периодических основах.Поскольку Timer гарантирует только «как минимум» период, его следует избегать для простого добавления счетчика, поскольку это может вызвать смещение в ваших вычислениях (для простых часов это, вероятно, не имеет большого значения, но если вам нужен какой-либо видточности, лучше избегать этого)

SimpleClock

import Foundation

public class SimpleClock {

    internal var startedAt: Date? = nil
    internal var totalRunningTime: TimeInterval = 0 // Used for pause/resume

    var isRunning: Bool = false {
        didSet {
            if isRunning {
                startedAt = Date()
            } else {
                totalRunningTime += currentCycleDuration
                self.startedAt = nil
            }
        }
    }

    // This is the amount of time that this cycle has been running,
    // that is, the amount of time since the clock was started to now.
    // It does not include other cycles
    internal var currentCycleDuration: TimeInterval {
        guard let startedAt = startedAt else {
            return 0
        }
        return Date().timeIntervalSince(startedAt)
    }

    func reset() {
        isRunning = false
        totalRunningTime = 0
    }

    // This is the "total" amount of time the clock has been allowed
    // to run for, excluding periods when the clock was paused
    var duration: TimeInterval {
        return totalRunningTime + currentCycleDuration
    }

}

Хорошо, это довольно базовая концепция.Это просто контейнер для записи, когда «цикл» запускается и останавливается, и для управления «общей» продолжительностью (циклы пуска / паузы / возобновления)

Это все хорошо и хорошо, но нам действительно нужен какой-то способопределить, имеет ли период «тайм-аут» или нет.

AlarmClock

import Foundation

class AlarmClock: SimpleClock {

    var timeout: TimeInterval = 0

    var hasExpired: Bool {
        return duration >= timeout
    }

    var timeRemaining: TimeInterval {
        return max(timeout - duration, 0)
    }

}

Все, что он делает, это добавляет концепцию периода «тайм-аут» и предоставляет некоторые дополнительные функции, которые позволяют использоватьлегко определить, истекли ли часы и сколько времени осталось

Пример

Хорошо, это все хорошо, но как это работает (и помогает нам)

Хорошо, это действительно простой пример.Он имеет метку и две кнопки.Одна кнопка запускает / приостанавливает часы, а другая сбрасывает их.

Метка отображает как время работы, так и оставшееся время будильника.Если часы истекают, они автоматически сбрасываются.

Класс содержит Timer, который периодически «тикает» и позволяет коду проверять текущее состояние будильника.

Clocky

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var durationLabel: UILabel!
    @IBOutlet weak var cycleButton: UIButton!
    @IBOutlet weak var resetButton: UIButton!

    let alarmClock: AlarmClock = {
        let clock = AlarmClock()
        clock.timeout = 10.0
        return clock
    }()

    var timer: Timer? = nil

    var durationFormatter: DateComponentsFormatter {
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = [.minute, .second]
        formatter.unitsStyle = .abbreviated
        return formatter
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func cycleClock(_ sender: Any) {
        alarmClock.isRunning = !alarmClock.isRunning
        if alarmClock.isRunning {
            timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
        } else {
            timer?.invalidate()
            timer = nil
        }
        updateDurationLabel()
        updateCycleButtonState()
    }

    @IBAction func restartClock(_ sender: Any) {
        timer?.invalidate()
        timer = nil

        alarmClock.reset()
        updateDurationLabel()
        updateCycleButtonState()
    }

    func updateCycleButtonState() {
        if alarmClock.isRunning {
            cycleButton.setTitle("Pause", for: [])
        } else {
            cycleButton.setTitle("Start", for: [])
        }
    }

    func updateDurationLabel() {
        durationLabel.text = "\(durationFormatter.string(from: alarmClock.duration)!)/\(durationFormatter.string(from: alarmClock.timeRemaining)!)"
    }

    @objc func tick() {
        print("click")
        updateDurationLabel()
        if alarmClock.hasExpired {
            restartClock(self)
        }
    }
}

Теперь вы также можете добавить своего рода «внутренний» поток, чтобы периодически проверять состояние часов и вызывать делегат, который затем может быть использован для обновленияПользовательский интерфейс, но намерение здесь состоит в том, чтобы разделить проблемы, и это означает, что вы не добавляете еще один поток в систему без необходимости (не говоря уже о том, что вы не можете этого сделать, но это просто еще один уровень сложности, который я не хотелдобавить;))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...