How can I make a countdown with NSTimer?

XcodeSwiftNstimer

Xcode Problem Overview


How can I make a countdown with an NSTimer using Swift?

Xcode Solutions


Solution 1 - Xcode

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

Solution 2 - Xcode

In 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
    }
}

Solution 3 - Xcode

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()
        }
    }
            
}

Solution 4 - Xcode

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)
    }

Solution 5 - Xcode

Variable for your timer

var timer = 60

NSTimer 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--
}

Solution 6 - Xcode

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
}

Solution 7 - Xcode

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)
    }

}

Solution 8 - Xcode

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()
     }
 }

Solution 9 - Xcode

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()
    }
}

Solution 10 - Xcode

Swift 4

Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateTime), userInfo: nil, repeats: true)

Update function

@objc func updateTime(){
    debugPrint("jalan")
}

Solution 11 - Xcode

> 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")
}

Solution 12 - Xcode

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
            }
        }

Solution 13 - Xcode

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
    }
    
}

https://github.com/nikae/CountDown-

Solution 14 - Xcode

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()
        }
        
    }
}

Solution 15 - Xcode

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
        
         }
    }
}

Solution 16 - Xcode

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")
        }
    }
}

Solution 17 - Xcode

You really shouldn’t. Grand Central Dispatch is much more reliable.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGiovanie RodzView Question on Stackoverflow
Solution 1 - XcodeBigmanView Answer on Stackoverflow
Solution 2 - Xcodeuser4956851View Answer on Stackoverflow
Solution 3 - XcodeMichael ShulmanView Answer on Stackoverflow
Solution 4 - XcodeGurjinder SinghView Answer on Stackoverflow
Solution 5 - XcodeHenny LeeView Answer on Stackoverflow
Solution 6 - XcodeGiangView Answer on Stackoverflow
Solution 7 - XcodewsnjyView Answer on Stackoverflow
Solution 8 - XcodeTomAshTeeView Answer on Stackoverflow
Solution 9 - XcodenullHip_nullSquareView Answer on Stackoverflow
Solution 10 - XcodeluhuiyaView Answer on Stackoverflow
Solution 11 - XcodeDeveshView Answer on Stackoverflow
Solution 12 - Xcoderashed mohammedView Answer on Stackoverflow
Solution 13 - XcodeNikaEView Answer on Stackoverflow
Solution 14 - XcodeSarvesh SridharView Answer on Stackoverflow
Solution 15 - XcodeNatallysonView Answer on Stackoverflow
Solution 16 - Xcodemichael satumbaView Answer on Stackoverflow
Solution 17 - XcodeMattView Answer on Stackoverflow