How can I make a countdown with NSTimer?
Olivia Zamora
How can I make a countdown with an NSTimer using Swift?
17 Answers
Question 1:
@IBOutlet var countDownLabel: UILabel!
var count = 10
override func viewDidLoad() { super.viewDidLoad() var timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)
}
func update() { if(count > 0) { countDownLabel.text = String(count--) }
}Question 2:
You can do both. SpriteKit is the SDK you use for scene, motion, etc. Simple View Application is the project template. They should not conflict
1In Swift 5.1 this will work:
var counter = 30
override func viewDidLoad() { super.viewDidLoad() Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
}
@objc func updateCounter() { //example functionality if counter > 0 { print("\(counter) seconds to the end of the world") counter -= 1 }
} 2 Swift 5 with Closure:
class ViewController: UIViewController {
var secondsRemaining = 30
@IBAction func startTimer(_ sender: UIButton) { Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in if self.secondsRemaining > 0 { print ("\(self.secondsRemaining) seconds") self.secondsRemaining -= 1 } else { Timer.invalidate() } }
} 3 Swift 4.1 and Swift 5. The updatetime method will called after every second and seconds will display on UIlabel.
var timer: Timer? var totalTime = 60 private func startOtpTimer() { self.totalTime = 60 self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true) } @objc func updateTimer() { print(self.totalTime) self.lblTimer.text = self.timeFormatted(self.totalTime) // will show timer if totalTime != 0 { totalTime -= 1 // decrease counter timer } else { if let timer = self.timer { timer.invalidate() self.timer = nil } } } func timeFormatted(_ totalSeconds: Int) -> String { let seconds: Int = totalSeconds % 60 let minutes: Int = (totalSeconds / 60) % 60 return String(format: "%02d:%02d", minutes, seconds) } 1 Variable for your timer
var timer = 60NSTimer with 1.0 as interval
var clock = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "countdown", userInfo: nil, repeats: true)Here you can decrease the timer
func countdown() { timer--
} 2 Swift 3
private let NUMBER_COUNT_DOWN = 3
var countDownLabel = UILabel()
var countDown = NUMBER_COUNT_DOWN
var timer:Timer?
private func countDown(time: Double)
{ countDownLabel.frame = CGRect(x: 0, y: 0, width: 300, height: 300) countDownLabel.font = UIFont.systemFont(ofSize: 300) countDownLabel.textColor = .black countDownLabel.center = CGPoint(x: self.view.frame.width / 2, y: self.view.frame.height / 2) countDownLabel.textAlignment = .center self.view.addSubview(countDownLabel) view.bringSubview(toFront: countDownLabel) timer = Timer.scheduledTimer(timeInterval: time, target: self, selector: #selector(updateCountDown), userInfo: nil, repeats: true)
}
func updateCountDown() { if(countDown > 0) { countDownLabel.text = String(countDown) countDown = countDown - 1 } else { removeCountDownLable() }
}
private func removeCountDownLable() { countDown = NUMBER_COUNT_DOWN countDownLabel.text = "" countDownLabel.removeFromSuperview() timer?.invalidate() timer = nil
} XCode 10 with Swift 4.2
import UIKit
class ViewController: UIViewController { var timer = Timer() var totalSecond = 10 override func viewDidLoad() { super.viewDidLoad() startTimer() } func startTimer() { timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true) } @objc func updateTime() { print(timeFormatted(totalSecond)) if totalSecond != 0 { totalSecond -= 1 } else { endTimer() } } func endTimer() { timer.invalidate() } func timeFormatted(_ totalSeconds: Int) -> String { let seconds: Int = totalSeconds % 60 return String(format: "0:%02d", seconds) }
} Swift 5 another way. Resistant to interaction with UI
I would like to show a solution that is resistant to user interaction with other UI elements during countdown. In the comments I explained what each line of code means.
var timeToSet = 0 var timer: Timer? ... @IBAction func btnWasPressed(_ sender: UIButton) { //Setting the countdown time timeLeft = timeToSet //Disabling any previous timers. timer?.invalidate() //Initialization of the Timer with interval every 1 second with the function call. timer = Timer(timeInterval: 1.0, target: self, selector: #selector(countDown), userInfo: nil, repeats: true) //Adding Timer to the current loop RunLoop.current.add(timer!, forMode: .common) } ... @objc func countDown() { if timeLeft > 0 { print(timeLeft) timeLeft -= 1 } else { // Timer stopping timer?.invalidate() } } For use in Playground for fellow newbies, in Swift 5, Xcode 11:
Import UIKit
var secondsRemaining = 10
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in if secondsRemaining > 0 { print ("\(secondsRemaining) seconds") secondsRemaining -= 1 } else { Timer.invalidate() }
} 3 Swift 4
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateTime), userInfo: nil, repeats: true)Update function
@objc func updateTime(){ debugPrint("jalan")
} Swift4
@IBOutlet weak var actionButton: UIButton! @IBOutlet weak var timeLabel: UILabel! var timer:Timer? var timeLeft = 60
override func viewDidLoad() { super.viewDidLoad() setupTimer()
}
func setupTimer() { timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(onTimerFires), userInfo: nil, repeats: true)
}
@objc func onTimerFires() { timeLeft -= 1 timeLabel.text = "\(timeLeft) seconds left" if timeLeft <= 0 { actionButton.isEnabled = true actionButton.setTitle("enabled", for: .normal) timer?.invalidate() timer = nil }
}
@IBAction func btnClicked(_ sender: UIButton) { print("API Fired")
} this for the now swift 5.0 and newst
var secondsRemaining = 60
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
}
@objc func updateCounter(){ if secondsRemaining > 0 { print("\(secondsRemaining) seconds.") secondsRemaining -= 1 } } Make Countdown app Xcode 8.1, Swift 3
import UIKit
import Foundation
class ViewController: UIViewController, UITextFieldDelegate { var timerCount = 0 var timerRunning = false @IBOutlet weak var timerLabel: UILabel! //ADD Label @IBOutlet weak var textField: UITextField! //Add TextField /Enter any number to Countdown override func viewDidLoad() { super.viewDidLoad() //Reset timerLabel.text = "" if timerCount == 0 { timerRunning = false }
} //Figure out Count method func Counting() { if timerCount > 0 { timerLabel.text = "\(timerCount)" timerCount -= 1 } else { timerLabel.text = "GO!" } } //ADD Action Button @IBAction func startButton(sender: UIButton) { //Figure out timer if timerRunning == false { _ = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(ViewController.Counting), userInfo: nil, repeats: true) timerRunning = true } //unwrap textField and Display result if let countebleNumber = Int(textField.text!) { timerCount = countebleNumber textField.text = "" //Clean Up TextField } else { timerCount = 3 //Defoult Number to Countdown if TextField is nil textField.text = "" //Clean Up TextField } } //Dismiss keyboard func keyboardDismiss() { textField.resignFirstResponder() } //ADD Gesture Recignizer to Dismiss keyboard then view tapped @IBAction func viewTapped(_ sender: AnyObject) { keyboardDismiss() } //Dismiss keyboard using Return Key (Done) Button func textFieldShouldReturn(_ textField: UITextField) -> Bool { keyboardDismiss() return true }
} Add this to the end of your code...
and call startTimer function with a parameter of where you want to count down to...
For example (2 hours to the future of the date right now) -> startTimer(for: Date().addingTimeInterval(60*60*2))
Click here to view a screenshot of iPhone Simulator of how it'll look
extension ViewController
{ func startTimer(for theDate: String) { let todaysDate = Date() let tripDate = Helper.getTripDate(forDate: theDate) let diffComponents = Calendar.current.dateComponents([.hour, .minute], from: Date(), to: tripDate) if let hours = diffComponents.hour { hoursLeft = hours } if let minutes = diffComponents.minute { minutesLeft = minutes } if tripDate > todaysDate { timer = Timer.scheduledTimer(timeInterval: 1.00, target: self, selector: #selector(onTimerFires), userInfo: nil, repeats: true) } else { timerLabel.text = "00:00:00" } } @objc func onTimerFires() { secondsLeft -= 1 //timerLabel.text = "\(hoursLeft):\(minutesLeft):\(secondsLeft)" timerLabel.text = String(format: "%02d:%02d:%02d", hoursLeft, minutesLeft, secondsLeft) if secondsLeft <= 0 { if minutesLeft != 0 { secondsLeft = 59 minutesLeft -= 1 } } if minutesLeft <= 0 { if hoursLeft != 0 { minutesLeft = 59 hoursLeft -= 1 } } if(hoursLeft == 0 && minutesLeft == 0 && secondsLeft == 0) { timer.invalidate() } }
} import UIKit
class ViewController: UIViewController { let eggTimes = ["Soft": 300, "Medium": 420, "Hard": 720] var secondsRemaining = 60 @IBAction func hardnessSelected(_ sender: UIButton) { let hardness = sender.currentTitle! secondsRemaining = eggTimes[hardness]! Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true) } @objc func countDown() { if secondsRemaining > 0 { print("\(secondsRemaining) seconds.") secondsRemaining -= 1 } }
} 2 You really shouldn’t. Grand Central Dispatch is much more reliable.
this is an egg timer.
import UIKit
class ViewController: UIViewController { let eggTimes = ["Soft": 0.1, "Medium": 2, "Hard": 3] var eggTime = 0 var timer = Timer() @IBOutlet weak var label: UILabel! @IBAction func b(_ sender: UIButton) { timer.invalidate() let hardness = sender.currentTitle! eggTime = Int(eggTimes[hardness]! * 60) timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(update), userInfo: nil, repeats: true) } @objc func update() { if (eggTime > 0) { print("\(eggTime) seconds") eggTime -= 1 } if (eggTime == 0){ label.text = ("done") } }
}