swiftcrackhead1
swiftcrackhead1

Reputation: 45

Disable a button for 30 seconds when pressed, enable again, then disabled when pressed again

I am trying to get this done. I want a button, that gets disabled once it is pressed for a certain amount of time. And once that time is over, the button is enabled again until it is pressed again, which then disables it for set time. I do not want the button to be enabled again easily by restarting the app. It has to stay disabled until the time is over and not until the next launch of the app .. so far my code is only working to disable the button once. It is not working, to enable it again after the time has passed. also the button is enabled again right after I relaunch the app. That is not supposed to happen.

Anyone have an idea, how I can get it working the way I want it to?

This is the code I have:

button.isUserInteractionEnabled = false
Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { _ in
    button.isUserInteractionEnabled = false
})

I have also tried it this way:

_ = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true)
_ = Timer.scheduledTimer(timeInterval: 0.0, target: self, selector: #selector(fireTimer2), userInfo: nil, repeats: false)

with the @objc being:

@objc func fireTimer() {
    print("Timer fired!")
}

@objc func fireTimer2() {
    print("Start timer.")
}

With this I wanted to try, if I can set a start time and a repeating time in the hopes to get things going with the button. I did not. Can anyone help me?

Appreciate it a lot! All the best

UPDATE, June 29:

This here is the code, I use for my button and to make the disable/enable function, that I want, work.

 @objc private let actionButton: UIButton = {
   let button = UIButton()
    button.setTitle("Button Title", for: .normal)
    button.titleLabel?.font = UIFont(name: "Times New Roman", size: 16)
    button.setTitleColor(.secondaryLabel, for: .normal)

    button.addTarget(self, action: #selector(didTapButton), for: .touchDown)

return button
}()

@objc func didTapButton() {
self.actionButton.isUserInteractionEnabled = false
Timer.scheduledTimer(withTimeInterval: 20, repeats: true) { _ in
    self.actionButton.isUserInteractionEnabled = true
}}

So how do I store the data from the timer in the core data(???) or UserDefaults(???) or where ever, so the timer doesnt reset when relaunching the app?

Upvotes: 4

Views: 877

Answers (1)

idz
idz

Reputation: 12988

The Timer class has an initializer init(fire:interval:repeats:block) that allows you to set a Date when it will fire. This will be useful for your problem. You have to be a little careful to make sure that you don't forget to schedule the timer, otherwise it will never fire.

You can use this to write a method like this:

func disable(button buttonToDisable: UIButton, until date: Date) {
    buttonToDisable.isEnabled = false
    let timer  = Timer.init(fire: date, interval: 0, repeats: false) { _ in
        buttonToDisable.isEnabled = true
    }
    RunLoop.current.add(timer, forMode: .common)
}

This method disables a specified button until a given date. Notice that false is passed for the repeats parameter. We only want this to run once.

With this method in hand you can now do the following when your button is pressed:

let disabledTimeInterval = TimeInterval(30.0)
    
@IBAction func buttonPressed(_ sender: Any) {
    let disabledUntil = Date().advanced(by: disabledTimeInterval)
    disable(button: self.button, until: disabledUntil)
}

This takes care of enabling and disabling the button while the app is running. But you also mentioned that you don't want users to be able to stop and start your app to get around the time out. You can handle this by saving the date the button should be disabled until in UserDefaults. The following code show how you can save and load a Date to UserDefaults.

    let buttonDisabledUntilDateKey = "buttonDisabledUntil"

    func save(disabledUntilDate date: Date) {
        UserDefaults.standard.set(date, forKey: buttonDisabledUntilDateKey)
    }
    
    func loadDisabledUntilDate() -> Date? {
        return UserDefaults.standard.object(forKey: buttonDisabledUntilDateKey) as? Date
    }

You can now modify the buttonPressed method to save this data:

@IBAction func buttonPressed(_ sender: Any) {
    let disabledUntil = Date().advanced(by: disabledTimeInterval)
    save(disabledUntilDate: disabledUntil)
    disable(button: self.button, until: disabledUntil)
}

Finally, when your view is about to appear, you should check whether the current time is before the time when the button should be reenabled and, if necessary, disable it.

override func viewWillAppear(_ animated: Bool) {
    let now = Date()
    if let buttonDisabledUntilDate = loadDisabledUntilDate(),
       now < buttonDisabledUntilDate {
        disable(button: self.button, until: buttonDisabledUntilDate)
    }
}

Upvotes: 1

Related Questions