Reputation: 388
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,
If there is anything that I didn't make clear just ask.
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
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