IOS swift countdown timer will not stop - ios

I am attempting to make a countdown timer that counts down from 60 seconds and then stops when it gets to 0. But for the timer keeps going into negative seconds. Any advice is appreciated. Code:
#IBOutlet var timeCounter: UILabel!
var second = 60
var timer = NSTimer()
var timerRunning = true
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setTimer()
timerCounting()
}
func setTimer(){
second -= 1
timeCounter.text = "\(second)"
}
func timerCounting(){
if(timerRunning == true){
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("setTimer"), userInfo: nil, repeats: true)
timerRunning = true
if second == 0 {
timerRunning = false
timer.invalidate()
}
}
}

You have to move the invalidation into the setTimer function since at its current location will never be triggered because timerCounting is only called once - in the beginning.
func setTimer(){
second -= 1
timeCounter.text = "\(second)"
if second == 0 {
timerRunning = false
timer.invalidate()
}
}

play with this in playground
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
import Foundation
#objc class C:NSObject {
var timer: NSTimer?
var second = 5
func setTimer(){
if c.second < 0 {
print("the timer fires the last time here ...")
timer?.invalidate()
} else {
print(second)
second -= 1
}
}
}
let c = C()
func timerCounting(){
c.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: c, selector: Selector("setTimer"), userInfo: nil, repeats: true)
}
timerCounting()

Related

Unexpected Output: I am using the below code to print out the timer according to the button pressed but timer is starting with 20 only. what's wrong?

import UIKit
class ViewController: UIViewController {
let eggTimes = ["Soft": 60,"Medium": 72,"Hard": 95]
var secondsRemaining = 20
var timer = Timer()
#IBAction func hardnessSelected(_ sender: UIButton) {
let hardness = sender.currentTitle!
var secondsRemaining = eggTimes[hardness]!
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}
#objc func timerAction()
{
if secondsRemaining > 0 {
print("\(secondsRemaining) seconds")
secondsRemaining -= 1
}
}
}
Unexpected Output: I am using the below code to print out the timer according to the button pressed but timer is starting with 20 only. what's wrong?
You are creating a new variable inside your Button function:
var secondsRemaining = eggTimes[hardness]!
instead you should assing your value. It should be:
self.secondsRemaining = eggTimes[hardness]!

When I pause my timer, then try to start it again, it does not run

I'm building an app in Swift 3. When I press start the first time my timer begins, but when I pause it and try to press start again, the timer does not budge. To give context, the timer, with an amount of time attached to it, is selected from a table. each time the timer load, the start button works initially.
protocol TimerViewControllerDelegate: class {
func viewController(_ controller: ViewController, didFinishEditing item: TaskData)
}
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var pauseButton: UIButton!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var timerTaskName: UILabel!
#IBOutlet weak var timerTimeSetting: UILabel!
#IBOutlet weak var progressView: UIProgressView!
weak var delegate: TimerViewControllerDelegate?
var timerTask: TaskData?
var timer: Timer?
var progressViewSpeed: Double = 0.0
#IBAction func cancel(_ sender: Any) {
timer?.invalidate()
dismiss(animated: true, completion: nil)
delegate?.viewController(self, didFinishEditing: timerTask!)
}
#IBAction func startButtonTapped(_ sender: Any) {
timerTask?.startTime = Date()
runTimer()
if timerTask?.isTaskRunning == true {
runTimer()
self.startButton.isEnabled = false
self.pauseButton.isEnabled = true
} else {
//retrieve start time and run
timerTask?.startTime = Date()
runTimer()
self.startButton.isEnabled = false
self.pauseButton.isEnabled = true
}
}
func runTimer() {
guard timer == nil else {
return
}
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
}
#IBAction func pauseButtonTapped(_ sender: UIButton) {
if timerTask?.isTaskRunning == true {
timer?.invalidate()
if let timerTask = timerTask, timerTask.isTaskRunning {
// Calculate the difference between now and when the timerTask was started
let difference = Int(Date().timeIntervalSince(timerTask.startTime!))
timerTask.taskRemaining -= difference
if timerTask.taskRemaining == 0 {
// Do something when there's no time remaining on the task?
}
timerTask.startTime = nil
}
}
else {
timerTask?.startTime = Date()
runTimer()
self.pauseButton.setTitle("Pause",for: .normal)
}
self.startButton.isEnabled = true
self.pauseButton.isEnabled = false
}
/*
#IBAction func resetButtonTapped(_ sender: Any) {
timer.invalidate()
seconds = 60
self.timerLabel.text = timeString(time: TimeInterval(seconds))
if self.resumeTapped == true {
self.resumeTapped = false
self.pauseButton.setTitle("Pause",for: .normal)
}
isTimerRunning = false
pauseButton.isEnabled = false
startButton.isEnabled = true
}
*/
func updateTimer() {
guard let timerTask = timerTask else {
return
}
if timerTask.taskRemaining < 1 {
timer?.invalidate()
timer = nil
//Send alert to indicate "time's up!"
} else {
updateTime()
}
progressViewSpeed = 1 / Double(timerTask.taskRemaining)
progressView.progress += Float(progressViewSpeed)
}
func timeString(time:TimeInterval) -> String {
let hours = Int(time) / 3600
let minutes = Int(time) / 60 % 60
let seconds = Int(time) % 60
return String(format:"%02i:%02i:%02i", hours, minutes, seconds)
}
override func viewDidLoad() {
super.viewDidLoad()
guard let timerTask = timerTask else {
return
}
if timerTask.isTaskRunning {
startButton.isEnabled = false
pauseButton.isEnabled = true
runTimer()
} else {
startButton.isEnabled = true
pauseButton.isEnabled = false
}
timerTaskName.text = timerTask.task
updateTime()
self.progressView.transform = CGAffineTransform.identity.rotated(by: CGFloat.pi / 2).scaledBy(x: 1, y: 150)
}
func updateTime() {
guard let timerTask = timerTask else {
return
}
if let startTime = timerTask.startTime {
// Calculate the difference between now and when the timerTask was started
let difference = Int(Date().timeIntervalSince(startTime))
if timerTask.taskRemaining == difference {
// Do something when there's no time remaining on the task
timer?.invalidate()
timer = nil
}
timerLabel.text = timeString(time: TimeInterval(timerTask.taskRemaining - difference))
} else {
timerLabel.text = timeString(time: TimeInterval(timerTask.taskRemaining))
}
}
}
Once you've invalidated an NSTimer, you can't use it again. You should create the new object.
See here for more From NSTimer Docs
Calling this method requests the removal of the timer from the current run loop; as a result, you should always call the invalidate method from the same thread on which the timer was installed. Invalidating the timer immediately disables it so that it no longer affects the run loop. The run loop then removes and releases the timer, either just before the invalidate method returns or at some later point. Once invalidated, timer objects cannot be reused.
You need to invalidate it and recreate it. "isPaused" bool to keep track of the state
var isPaused = true
var timer: Timer?
#IBAction func pauseResume(sender: AnyObject) {
if isPaused{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
pauseButton.isHidden = false
startButton.isHidden = true
isPaused = false
} else {
pauseButton.isHidden = true
startButton.isHidden = false
timer.invalidate()
isPaused = true
}
}

Swift 2 - Timed Actions one second apart?

I'm trying to get output like so:
1 (then a one second delay)
Hello
2 (then a one second delay)
Hello
3 (then a one second delay)
Hello
But instead I get
1
2
3 (then a one second delay)
Hello
Hello
Hello
Here's my for loop invoking the NSTimer
var timer = NSTimer()
for i in 1...3 {
print("\(i)");
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(MainVPScreenViewController.printTest), userInfo: nil, repeats: false)
}
And here's the selector method:
func printTest() {
print("Hello")
}
Thanks in advance for any help you can provide
Try this solution without NSTimer:
var i = 1
func printHello() {
print(i)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
print("Hello")
i +=1
if i <= 3 {
printHello()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
printHello()
}
I need 2 NSTimers to do this, this is my approach
class ViewController: UIViewController {
var i = 1
override func viewDidLoad() {
super.viewDidLoad()
beginPrinting()
}
func beginPrinting() {
var timer2 = NSTimer()
if(i <= 100)
{
timer2 = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(self.printWithDelay), userInfo: nil, repeats: false)
}
}
func printWithDelay()
{
var timer = NSTimer()
print("\(i)");
i += 1
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(self.printTest), userInfo: nil, repeats: false)
}
func printTest() {
print("Hello")
beginPrinting()
}
}
Hope this helps you
Use timer with repeat to true. So in your view controller would be like this
var timer = NSTimer()
var counter = 0
var max = 10
let delay = 1 // in second
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self,
selector: #selector(self.printTest), userInfo: nil, repeats: true)
}
func printTest() {
counter += 1
print(counter)
print(hello)
if counter == maxNumber {
timer.invalidate()
}
}
This does it with repeat false, and is set up to be in a playground:
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
#objc class Foo: NSObject {
static var timer = NSTimer()
var i:Int
override init() {
Foo.timer = NSTimer()
i = 1
}
func schedule() {
print("\n\(i)");
i += 1
Foo.timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: #selector(printTest),
userInfo: nil,
repeats: false)
}
#objc func printTest() {
print("Hello")
if i < 5 {
schedule()
}
}
}
let bar = Foo()
bar.schedule()

How can I launch series of timer in Swift 2.0?

I need launch the timer few times in sequence (one after another). And of course I need update Label with timer results.
For example, I have two periods (50 sec and 10 sec) and I need to make a series of periods: 50-10-50-10-50-10.
How can I do it?
import UIKit
class StartTimerViewController: UIViewController {
let firstPeriodTime = 50
let secondPeriodTime = 10
var currentPeriodTime: Int!
let repetitionTime = 3
var timer: NSTimer!
var timeCount = 0
#IBOutlet weak var timerLabel: UILabel!
// MARK: - IBAction method implementation
#IBAction func start(sender: AnyObject) {
// I know it's wrong... This is my question!!!!!
var i = 1
while i <= repetitionTime {
currentPeriodTime = firstPeriodTime
startTimer()
currentPeriodTime = secondPeriodTime
startTimer()
i = i + 1
}
}
// MARK: - Timer method implementation
func startTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: "updateCounter", userInfo: nil, repeats: true)
print("timer start")
}
func updateCounter() {
if timeCount < currentPeriodTime {
timeCount++
let currentTime = Double(currentPeriodTime - timeCount)
timerLabel.text = timeString(currentTime)
}
else {
timer.invalidate()
timeCount = 0
}
}
func timeString(time:NSTimeInterval) -> String {
let minutes = Int(time) / 60
let seconds = time - Double(minutes) * 60
return String(format:"%02i:%02i",minutes,Int(seconds))
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Please use the code below
#IBOutlet weak var _lblTimer: UILabel!
var timer = NSTimer()
var intValue = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update50:", userInfo: nil, repeats: true)
}
func update50(timer : NSTimer){
intValue += 1
_lblTimer.text = intValue.description
if(intValue == 50){
intValue = 0
timer.invalidate()
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update10:", userInfo: nil, repeats: true)
}
}
func update10(timer : NSTimer){
intValue += 1
_lblTimer.text = intValue.description
if(intValue == 10){
intValue = 0
timer.invalidate()
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update50:", userInfo: nil, repeats: true)
}
}

How to use a countdown timer to stop a game - iOS [SWIFT] -

My game is supposed to be stopped after 60s. But nothing happens with my timer code.
var timer = NSTimer()
var counter:Int = 60
var labelCounter:SKLabelNode = SKLabelNode()
Here is the code in my GameScene class :
func startTimer()
{
timer = NSTimer.scheduledTimerWithTimeInterval(1.0
, target: self, selector: Selector("updateTimer:"), userInfo: nil, repeats: true)
}
func updateTimer(dt:NSTimer)
{
counter--
if counter == 0 {
timer.invalidate()
removeCountDownTimerView()
} else{
labelCounter.text = "\(counter)"
}
}
func removeCountDownTimerView()
{
scene.view.paused = true
}
thank you for your insight :-)
Try something like this....
override func viewDidLoad() {
super.viewDidLoad()
//calling the wait function
self.callForWait()
}
func callForWait(){
//setting the delay time 60secs.
let delay = 60 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue()) {
//call the method which have the steps after delay.
self.stepsAfterDelay()
}
}
func stepsAfterDelay(){
//your code after delay takes place here...
}
I had this in a game. Hope it helps:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
startGame()
}
var startTime = NSTimeInterval()
var timer = NSTimer()
var gameTime:Double = 10
func startGame() {
let aSelector : Selector = "updateTime"
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: aSelector, userInfo: nil, repeats: true)
startTime = NSDate.timeIntervalSinceReferenceDate()
}
func updateTime() {
var currentTime = NSDate.timeIntervalSinceReferenceDate()
var elapsedTime = currentTime - startTime
var seconds = gameTime-elapsedTime
if seconds > 0 {
elapsedTime -= NSTimeInterval(seconds)
println("\(Int(seconds))")
} else {
timer.invalidate()
}
}
}

Resources