nix.codes
nix.codes

Reputation: 388

How to Implement separate Minute and Second Labels for a Countdown Timer

Okay, so I am working on a countdown timer function as part of an app I am working on. I have run into a bit of an issue in how to implement the timer and how it appears on screen. My two issues are,

  1. Right now I only have the timer able to countdown seconds. The timer will always have a fixed countdown time of 10 minutes.
  2. I have two separate labels for the timer as I want them to display differently on screen. Is it possible to have the minutes and second variables being pushed to separate labels on the display?

If there is anything that I didn't make clear just ask.

enter image description here

    import UIKit

    class ViewController: UIViewController {

    //MARK: - Countdown Timer Connections
    @IBOutlet weak var minuteLabel: UILabel!
    @IBOutlet weak var secondLabel: UILabel!

    //MARK: - Seed Connections
    @IBOutlet weak var seedSlot1: UIImageView!
    @IBOutlet weak var seedSlot2: UIImageView!
    @IBOutlet weak var seedSlot3: UIImageView!
    @IBOutlet weak var seedSlot4: UIImageView!

    //MARK: - Start/Pause Button Connection
    @IBOutlet weak var startButton: UIButton!
    @IBOutlet weak var stopButton: UIButton!
    @IBOutlet weak var pauseButton: UIButton!

    //MARK: - Variables
    var timer = Timer()

    var isTimerRunning : Bool = false
    var resumeTapped: Bool = false
    var minutes : Int = 24
    var seconds: Int = 10

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        pauseButton.setImage(nil, for: .normal)
        stopButton.setImage(nil, for: .normal)
    }



    //MARK: Timer Control Functions
    //MARK: - Start Timer
    @IBAction func startTimer(_ sender: UIButton) {
        if isTimerRunning == false {
            isTimerRunning = true
            setButtons()

            timer = Timer.scheduledTimer(
                timeInterval: 1,
                target: self,
                selector: (#selector(ViewController.updateTimer)),
                userInfo: nil,
                repeats: true
            )

            print("The timer is currently running: \(isTimerRunning)")
        } else {
            isTimerRunning = false
            setButtons()
            print("The timer is currently running: \(isTimerRunning)")
        }
        print(secondLabel.text)
    }

    //MARK: - Stop Timer
    @IBAction func stopTimer(_ sender: UIButton) {
        timer.invalidate()
        isTimerRunning = false
        seconds = 60
        minuteLabel.text = "\(minutes)"
        secondLabel.text = "\(seconds)"
        setButtons()
    }

    //MARK: - Pause Timer
    @IBAction func pauseTimer(_ sender: UIButton) {
        if resumeTapped == false {
            timer.invalidate()
            isTimerRunning = false
            setButtons()
        } else {
            startTimer(startButton)
            isTimerRunning = true
            setButtons()
        }
    }

    func timeString (time:TimeInterval) -> String {
        let secondValue = Int(time) & 60
        let minuteValue = Int(time) / 60 % 60
        return String(format: "%02i", minuteValue, secondValue)
    }

    //MARK: - Update Timer
    @objc func updateTimer() {
        seconds -= 1     //This will decrement(count down)the seconds.
        secondLabel.text = timeString(time: TimeInterval(seconds)) //This will update the seconds text label
    }

Upvotes: 1

Views: 672

Answers (1)

AlexSmet
AlexSmet

Reputation: 2161

It's a bad idea if you want to calculate seconds manually by decrement value of seconds variable. Because Timer does not guarantee that it will fire exactly after the 1-second interval. In my opinion, the preferred way if you will calculate a time interval between the time when timer was started and the current time.

class ViewController: UIViewController {

    @IBOutlet weak var minuteLabel: UILabel!
    @IBOutlet weak var secondLabel: UILabel!


    var timer: Timer?

    let countDownInterval: TimeInterval = 10*60 // minutes*seconds
    var finishTime: Date!
    var pauseStartTime: Date?    

    @IBAction func startTimer(_ sender: UIButton) {
        if let pause = pauseStartTime {
            let pauseInterval = Date().timeIntervalSince(pause)
            finishTime.addTimeInterval(pauseInterval)
        } else {
            finishTime = Date().addingTimeInterval(countDownInterval)
        }

        pauseStartTime = nil
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] _ in self?.changeLabels() })
    }

    @IBAction func pauseTimer(_ sender: UIButton) {
        pauseStartTime = Date()
        timer?.invalidate()
    }

    func changeLabels() {
        let currentTime = Date()

        guard  currentTime < finishTime else {
            // Countdown finished
            timer?.invalidate()
            minuteLabel.text = String(format: "%02.f", 0)
            secondLabel.text = String(format: "%02.f", 0)
            return
        }

        let currentInterval = finishTime.timeIntervalSince(currentTime)
        let minutes = (currentInterval / 60).rounded(.down)
        let seconds = currentInterval.truncatingRemainder(dividingBy: 60).rounded()
        minuteLabel.text = String(format: "%02.f", minutes)
        secondLabel.text = String(format: "%02.f", seconds)
    }
}

Upvotes: 1

Related Questions