xcode 10.1: Timer stops at 1 not 0 - swift

Yep, I have seen a few questions similar to mine but for some reason, I couldn't duplicate it! If I use == or <= with If both are giving me stop at 1. The only < gave me the 0 stops which are good, but very rare I got -1. Any help, please?
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var startButton: UIButton!
var timer = Timer()
var timeLeft = 10
override func viewDidLoad() {
timeLabel.text = String(10)
super.viewDidLoad()
}
#IBAction func pressTimer(_ sender: Any) {
startButton.isEnabled = false
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(startTime), userInfo: nil, repeats: true)
}
#objc func startTime() {
timeLeft -= 1
timeLabel.text = "\(timeLeft)"
if timeLeft < 0 {
startButton.isEnabled = false
self.timer.invalidate()
}
}
}

My suggestion is to declare the timer as optional and check for zero before decrementing the counter.
And set the counter to 10 in the pressTimer method
class ViewController: UIViewController {
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var startButton: UIButton!
var timer : Timer?
var timeLeft = 0
#IBAction func pressTimer(_ sender: Any) {
startButton.isEnabled = false
timeLeft = 10
timeLabel.text = String(timeLeft)
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(startTime), userInfo: nil, repeats: true)
}
}
#objc func startTime()
{
if timeLeft == 0 {
startButton.isEnabled = false // shouldn't it be true??
timer?.invalidate()
timer = nil
} else {
timeLeft -= 1
timeLabel.text = String(timeLeft)
}
}
}

Related

Timer counts but doesn´t desplay

I just started to learn how to code and speak English^^
When I go from secondViewController to ViewController, a timer starts. A label shows the timer.
My problem is, when I go from secondViewController to ViewController for the second time, the label doesn´t show the timer. But the timer continue to count (I printed it out). Why the label doesn´t shoews the timer ?
I would be very grateful for your help
ViewController
var habit = 0
var statusFirst = false
class ViewController: UIViewController {
var firstTitel = ""
var secondTitels = ""
var timerTime = 0
var timer = Timer()
#IBOutlet weak var titelLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var secondTitel: UILabel!
#IBOutlet weak var secondDate: UILabel!
#objc func processTimer() {
timerTime += 1
dateLabel.text = String(timerTime)
print(timerTime)
}
override func viewDidLoad() {
super.viewDidLoad()
// Hide Label - START
print(habit)
if habit == 0 {
titelLabel.isHidden = true
secondTitel.isHidden = true
dateLabel.isHidden = true
secondDate.isHidden = true
timer.invalidate()
}else if habit == 1 {
titelLabel.isHidden = false
secondTitel.isHidden = true
dateLabel.isHidden = false
secondDate.isHidden = true
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.processTimer), userInfo: nil, repeats: true)
}else if habit == 2 {
titelLabel.isHidden = false
secondTitel.isHidden = false
dateLabel.isHidden = false
secondDate.isHidden = false
}
// Hide Label - END
let titelObject = UserDefaults.standard.object(forKey: "firstTitel")
if let titel = titelObject as? String {
titelLabel.text = titel
}
let titellObject = UserDefaults.standard.object(forKey: "secondTitel")
if let titell = titellObject as? String {
secondTitel.text = titell
}
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
SecondViewController
class SecondViewController: UIViewController {
var titelSecondViewController = ""
var dateSecondViewController = 0
#IBOutlet weak var titelField: UITextField!
#IBOutlet weak var dateField: UITextField!
#IBOutlet weak var okButton: UIButton!
#IBAction func okButtonAction(_ sender: Any) {
titelSecondViewController = titelField.text!
if let datefield = dateField.text {
if datefield == "" {
dateSecondViewController = 0
}else{
dateSecondViewController = Int(datefield)!
}
}else{
print("lol")
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
// Segue - Start
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toViewController" {
let viewController = segue.destination as! ViewController
habit += 1
print(habit)
if habit == 1 {
statusFirst = true
UserDefaults.standard.set(titelSecondViewController, forKey: "firstTitel")
}else if habit == 2{
UserDefaults.standard.set(titelSecondViewController, forKey: "secondTitel")
}else{
return
}
}
}
// Segue - End
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In first case habit = 1 so the timer is called
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.processTimer), userInfo: nil, repeats: true)
since the timer has a strong reference and you don't invalidate() it inside viewDidDisappear , it keeps the VC in memory after you dismiss it
//
In second time habit = 2 and you don't init the time inside it's if statement then the label of the second instance ( the presented one ) doesn't update , while the hidden dismissed one do

How do I set a label to a value from a separate table view controller?

So I'm setting up a timer in swift that takes text entered from another view controller. I'm not sure how to set the timer label as the value "timerTime" which has a member called "time" from another controller.
import UIKit
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!
var timerTask: TaskData?
var timerTime: TaskData?
var seconds = 100
var timer = Timer()
var isTimerRunning = false
var resumeTapped = false
#IBAction func cancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func startButtonTapped(_ sender: Any) {
if isTimerRunning == false {
runTimer()
self.startButton.isEnabled = false
}
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
isTimerRunning = true
pauseButton.isEnabled = true
}
#IBAction func pauseButtonTapped(_ sender: UIButton) {
if self.resumeTapped == false {
timer.invalidate()
self.resumeTapped = true
self.pauseButton.setTitle("Resume",for: .normal)
} else {
runTimer()
self.resumeTapped = false
self.pauseButton.setTitle("Pause",for: .normal)
}
}
#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() {
if seconds < 1 {
timer.invalidate()
//Send alert to indicate "time's up!"
} else {
seconds -= 1
timerLabel.text = timeString(time: TimeInterval(seconds))
}
}
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()
pauseButton.isEnabled = false
if let task = timerTask {
timerTaskName.text = task.task
}
if let timerTimeLeft = timerTime {
timerTimeSetting.text = timerTimeLeft.time
}
self.timerLabel.text = timeString(time: TimeInterval(seconds))
}
}
Essentially I'm trying to get timerTimeLeft.time into my seconds variable. I've tried many different things but at I'm just stuck.
You need to add the timer to the runloop. This:
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
isTimerRunning = true
pauseButton.isEnabled = true
}
Should be
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: .defaultRunLoopMode) // <-- Notice this
isTimerRunning = true
pauseButton.isEnabled = true
}

Counter wont subtract on button press?

I am trying to get my setCount to -1 each time the endSetPressed action is called.
I have included setCount -= 1 to the updateTimer function so that when endSetPressed is pressed, it should -1 from the setCount and then start the restCount timer. However in practice it doesnt seem to show it doing the -1 in the app it just stays fixed at the starting setCount value.
Another issue was that I want to be able to see the value of restRemainingCountdownLabel as the user is setting the restStepperValueChanged value, i figured this was done via 'restRemainingCountdownLabel.text = String(restCount)' however as im using 'restCount = Int(sender.value)*60' to generate a value in minutes, its showing the restRemainingCountdownLabel in seconds rather than mins, Appreciate some guidance on that one too!
Here is my code:
#IBOutlet weak var restRemainingCountdownLabel: UILabel!
#IBOutlet weak var setsRemainingCountdownLabel: UILabel!
#IBOutlet weak var numberOfSetsLabel: UILabel!
#IBOutlet weak var numberOfRestLabel: UILabel!
#IBOutlet weak var adjustSetsStepper: UIStepper!
#IBOutlet weak var adjustRestStepper: UIStepper!
var restTimer: Timer?
var restCount = 0
var setCount = 0
#IBAction func endSetPressed(_ sender: Any) {
restTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(RestController.updateTimer), userInfo: nil, repeats: true)
}
#IBAction func setStepperValueChanged(_ sender: UIStepper) {
numberOfSetsLabel.text = Int(sender.value).description
setCount = Int(sender.value)
setsRemainingCountdownLabel.text = String(setCount)
}
#IBAction func restStepperValueChanged(_ sender: UIStepper) {
numberOfRestLabel.text = Int(sender.value).description
restCount = Int(sender.value)*60
restRemainingCountdownLabel.text = String(restCount)
}
#IBAction func resetSetsButton(_ sender: Any) {
//setCount = Int
}
override func viewDidLoad() {
super.viewDidLoad()
}
func updateTimer() {
if (setCount > 0){
setCount -= 1
}
if (restCount > 0){
let minutes = String(restCount / 60)
let seconds = String(restCount % 60)
restRemainingCountdownLabel.text = minutes + ":" + seconds
restCount -= 1
}
}
Have a look at your updateTimer() method, first line:
if (setCount > 0)
if setCount > 0 then subtract 1 from setCount
but...here you've declared setCount with a value of 0
var setCount = 0
So, you never end up in your if part :)
How to Debug This
The next time you have a problem like this, try adding some print() statements to your code.
In your case you could do something like this:
#IBAction func endSetPressed(_ sender: Any) {
print("endSetPressed")
restTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(RestController.updateTimer), userInfo: nil, repeats: true)
}
#IBAction func setStepperValueChanged(_ sender: UIStepper) {
numberOfSetsLabel.text = Int(sender.value).description
setCount = Int(sender.value)
setsRemainingCountdownLabel.text = String(setCount)
}
#IBAction func restStepperValueChanged(_ sender: UIStepper) {
numberOfRestLabel.text = Int(sender.value).description
restCount = Int(sender.value)*60
restRemainingCountdownLabel.text = String(restCount)
}
#IBAction func resetSetsButton(_ sender: Any) {
//setCount = Int
}
override func viewDidLoad() {
super.viewDidLoad()
}
func updateTimer() {
print("updateTimer")
if (setCount > 0){
print("setCount > 0")
setCount -= 1
print("setCount is now \(setCount)")
}
if (restCount > 0){
print("restCount > 0")
let minutes = String(restCount / 60)
let seconds = String(restCount % 60)
restRemainingCountdownLabel.text = minutes + ":" + seconds
restCount -= 1
print("restCount is now \(restCount) - minutes: \(minutes) - seconds: \(seconds)")
}
}
That should give you some indications about what is going on and the "path" your code follows.
Hope that helps you.

Stopwatch code Issue

I am trying to create a stopwatch app, for some reason when I press the start button in the app, instead of it going, 1,2,3,4,5 etc. It shows this '<'. I have gone over the code but I can find nothing.
class ViewController: UIViewController {
var timer = NSTimer()
var time = 0
func result() {
time + 1
timeLabel.text = "\(timer)"
}
#IBOutlet var timeLabel: UILabel!
#IBAction func stop(sender: AnyObject) {
timer.invalidate()
time = 0
timeLabel.text = "0"
}
#IBAction func timeButton(sender: AnyObject) {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("result"), userInfo: nil, repeats: true)
}
}
You have a typo: timeLabel.text = "\(timer)" should be timeLabel.text = "\(time)".
Also, time + 1 should be time += 1. With those changes, the following code works:
class ViewController: UIViewController {
var timer = NSTimer()
var time = 0
func result() {
time += 1
timeLabel.text = "\(time)"
}
#IBOutlet var timeLabel: UILabel!
#IBAction func stop(sender: AnyObject) {
timer.invalidate()
time = 0
timeLabel.text = "0"
}
#IBAction func timeButton(sender: AnyObject) {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(result), userInfo: nil, repeats: true)
}
}

Building a small timer app, why won't app timer stop both labels?

I'm in the process of building a timer app
I have a button that starts the timer and changes both labels
I have another button that stops the timer with .invalidete.
the problem is when the timer starts both labels change at the set rate they are suppose to
But when I hit the stop button only the 2nd timer label stops changing, the 1st label seems to keep going I don't know why
import UIKit
class ViewController: UIViewController {
var timer = NSTimer()
var counter = 0
var counter2 = 0
#IBOutlet weak var label: UILabel!
#IBOutlet weak var label2: UILabel!
#IBAction func start(sender: AnyObject){
counter = 0
label.text = String(counter)
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "updateCounter", userInfo: nil, repeats: true)
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter2", userInfo: nil, repeats: true)
}
func updateCounter2(){
counter2 += 1
label2.text = String(counter2)
}
func updateCounter(){
counter += 1
label.text = String(counter)
}
#IBAction func stop(sender: AnyObject) {
timer.invalidate()
timer.invalidate()
}
}
What you wan't to do is something like this:
var timer:NSTimer!
var timer2:NSTimer!
var counter = 0
var counter2 = 0
#IBOutlet weak var label: UILabel!
#IBOutlet weak var label2: UILabel!
#IBAction func start(sender: AnyObject){
counter = 0
label.text = String(counter)
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "updateCounter", userInfo: nil, repeats: true)
timer2 = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateCounter2", userInfo: nil, repeats: true)
}
func updateCounter2(){
counter2 += 1
label2.text = String(counter2)
}
func updateCounter(){
counter += 1
label.text = String(counter)
}
#IBAction func stop(sender: AnyObject) {
timer.invalidate()
timer2.invalidate()
}
Watch this talk in value types from WWDC 2015, it explains a couple of things about OOP that you might find useful.