2

looking for some help for this, I have a timer that works after submitting a password which is great, but I then need to disable the button after the timer starts and is disabled for a period of time, (in the code I have entered a nominal 90 seconds)

however the button is not disabling.

if anybody could show me where I am going wrong that would be awesome.

    import UIKit

class appiHour: UIViewController {

var timer = Timer()
var counter = 60
var password_Text: UITextField?

func enableButton() {
    self.timerStartButton.isEnabled = true
}

@IBOutlet weak var timerLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
    //   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.
}

@IBAction func timerStartButton(_ sender: Any) {

    var password_Text: UITextField?

    let alertController = UIAlertController(title: "To start your own 2 Cocktails for £10 APPi Hour", message: "get a memeber of the team to enter the password, but use it wisely, as you can only use it once per day, with remember great power comes great responsability", preferredStyle: UIAlertControllerStyle.alert)

    let tickoff_action = UIAlertAction(title: "let the APPiness commence", style: UIAlertActionStyle.default) {
        action -> Void in

        self.timerStartButton.isEnabled = false
        Timer.scheduledTimer(timeInterval: 90, target: self, selector: #selector(appiHour.enableButton), userInfo: nil, repeats: false)

        if let password = password_Text?.text{
            print("password = \(password)")
            if password == "baruba151" {
                self.counter = 60
                self.timerLabel.text = String(self.counter)

                self.timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(appiHour.updateCounter), userInfo: nil, repeats: true)
            }


        } else {
            print("No password entered")
        }


    }

    alertController.addTextField { (txtpassword) -> Void in
        password_Text = txtpassword
        password_Text!.isSecureTextEntry = true
        password_Text!.placeholder = ""

    }



    alertController.addAction(tickoff_action)
    self.present(alertController, animated: true, completion: nil)



}

@IBOutlet weak var timerStartButton: UIButton!


func updateCounter() {

    counter -= 1
    timerLabel.text = String(counter)

    if counter == 0{

        timer.invalidate()
        counter = 0



    }


}

}

As a secondary question is it possible to run the timer while the app is in the background? i know apple frowns on this aside for Sat Nav, Music apps etc. But is there a method in which the timer is held and a notification is sent locally letting the user know the timer has ended?

thanks in advance.

Matthew Webster
  • 137
  • 2
  • 12
  • I see no "self.timerStartButton.isEnabled = false" in your code anywhere. I suspect that is why you're not getting your button disabled. As for running the timer in the background, yes & no. You can discourage iOS from terminating your app for up to 3 minutes. Look up "UIApplication.shared.beginBackgroundTask()". However, you won't be able to run your timer forever. Eventually, iOS will force your app to sleep. – JacobJ Nov 16 '16 at 19:00
  • As I can't see your Interface Builder layout, I'm assuming you have two actions hooked up to the same button's TouchUpInside event. (Start_Button and timerStartButton). That's fine, but you need to make sure both are attached to your button. Right click on your button and make sure you see both are hooked up appropriately. – JacobJ Nov 16 '16 at 19:08
  • yeah, just noticed, the second action shouldn't have been there as there is only one button action required, I have replaced the code as it should be, but it is now crashing as the timer starts after validation. any suggestions where the "self.timerStartButton.isEnabled = false" should go? – Matthew Webster Nov 16 '16 at 19:25
  • Where you have it is fine - just do a ctrl-click on your button and drag it over your "timerStartButton" function. You'll need to use the split code view to do this. This should make it so touching the button actually fires the action. – JacobJ Nov 16 '16 at 19:29
  • Timers are not the most accurate way to count time/seconds. For example: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Timers/Articles/timerConcepts.html#//apple_ref/doc/uid/20000806-SW2 Even if everything runs and the user doesn't tab out of the app the total time passed, after the timer has fired 60 times, will probably be more than 60 seconds. – boidkan Nov 16 '16 at 19:55
  • This: `Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds. If a timer’s firing time occurs during a long callout or while the run loop is in a mode that is not monitoring the timer, the timer does not fire until the next time the run loop checks the timer. Therefore, the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time. ` – boidkan Nov 16 '16 at 19:57

2 Answers2

2

I suspect that your action may not be hooked up to your button. I just tried the following code with no issues. The button gets disabled, and then enabled 5 seconds later:

class ViewController: UIViewController {

    @IBOutlet weak var myButton: UIButton!

    @IBAction func ButtonPressed(_ sender: Any) {
        myButton.isEnabled = false
        Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(myTimerTick), userInfo: nil, repeats: false)
    }

    func myTimerTick() {
        myButton.isEnabled = true
    }
}

So make sure your outlets and actions are hooked up to the button correctly. If you right click on your button, you should see the dots filled in next to the outlet and action. You should see similarly filled in dots in your code.

You can further verify it is hooked up by placing a breakpoint in your "timerStartButton" method and making sure that breakpoint is hit.

Edit to further clarify: You need to connect your code to your Interface build objects. See this article from Apple for a complete tutorial on how to do that.

enter image description here

JacobJ
  • 3,677
  • 3
  • 28
  • 32
0

I'm not 100% sure if this is what you mean. But this would at least satisfy the first part of your request: disable a button whilst a timer is running, and re-enable it once the timer stops.

@IBOutlet weak var myButton: UIButton!
@IBOutlet weak var timerCount: UILabel!

@IBAction func buttonPressed(_ sender: UIButton) {
    var count = 0
    sender.isEnabled = false

    Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [unowned self] timer in

        count += 1

        if count == 5 {
            count = 0
            sender.isEnabled = true
            timer.invalidate()
        }

        self.timerCount.text = "\(count)"
    }
}

Here's a couple of screenshots of what you get. It's enabled when the user starts off, disabled whilst the count is going then reverts back to its original state with counter at 0 and button enabled. Is that what you're going for?

enter image description here enter image description here

As far as your second question, what do you mean by

the timer is held

Do you want the timer to keep running whilst the app is in the background, then update the user once the timer has elapsed? If so, take a look at this answer which should point you in the right direction: Continue countdown timer when app is running in background/suspended

Community
  • 1
  • 1
Kyle G
  • 4,347
  • 4
  • 26
  • 39
  • essentially yes, but then if they bring the app back into the foreground it will show the timer with an adjusted current value. i.e. if it starts at a hour is moved to the background after 35 minutes it is brought back to the front and the timer will show 25 minutes. – Matthew Webster Nov 16 '16 at 21:03