How to disable UIAlertController Buttons?

Hi all,
I'm struggling to find a way to disable buttons in a UIAlertController of .alert style. I have a textfield, for entering the current password, a button for changing the current password and a button for deleting it. I'd like to disable both password buttons until the current password is correctly entered into the textfield, but I'm struggling to find the solution. If anyone can point me in the right direction it would be much appreciated.

Answered by Claude31 in 395709022

Here is a template for this (example: ask for a city name ; Search button enabled if name non empty).

Alert is called when tapping a button: here is the IBAction:



    var alert : UIAlertController?          // Declared in the class

    @IBAction func testAlert(_ sender: Any) {
        //1. Create the alert controller.
        alert = UIAlertController(title: "Search city", message: "City name ", preferredStyle: .alert)
   
        //2. Add the text field.
        alert?.addTextField(configurationHandler: { (textField) -> Void in
            textField.placeholder = ""
            textField.keyboardType = UIKeyboardType.emailAddress // To have @ ; or any other keyboard type you wish
            textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)     // Action when we type in textField
        })
   
        //3. Grab the value from the text field. At the end, when hitting search
        let yesAction = UIAlertAction(title: "Search", style: .default, handler: { (action) -> Void in
            let textField = self.alert?.textFields![0]
            if textField?.text! == "" {     // When we have hit Search, if enabled
                print("empty")
            } else {
                print("not empty", textField?.text! ?? "")
            }
        })
        yesAction.isEnabled = false
        alert?.addAction(yesAction)   // Disabled on alert creation
   
        // 4. Present the alert.
        self.present(alert!, animated: true, completion: nil)
    }

// Test if textField empty ; note that it was created disabled
    @objc func alertTextFieldDidChange(_ sender: UITextField) {
        alert?.actions[0].isEnabled = sender.text!.count > 0
    }


Hope that helps.

I've discovered .isEnabled for the buttons, so that's a step forward. I'm guessing now that they might perhaps be enabled within some textfield delegate method.

Accepted Answer

Here is a template for this (example: ask for a city name ; Search button enabled if name non empty).

Alert is called when tapping a button: here is the IBAction:



    var alert : UIAlertController?          // Declared in the class

    @IBAction func testAlert(_ sender: Any) {
        //1. Create the alert controller.
        alert = UIAlertController(title: "Search city", message: "City name ", preferredStyle: .alert)
   
        //2. Add the text field.
        alert?.addTextField(configurationHandler: { (textField) -> Void in
            textField.placeholder = ""
            textField.keyboardType = UIKeyboardType.emailAddress // To have @ ; or any other keyboard type you wish
            textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)     // Action when we type in textField
        })
   
        //3. Grab the value from the text field. At the end, when hitting search
        let yesAction = UIAlertAction(title: "Search", style: .default, handler: { (action) -> Void in
            let textField = self.alert?.textFields![0]
            if textField?.text! == "" {     // When we have hit Search, if enabled
                print("empty")
            } else {
                print("not empty", textField?.text! ?? "")
            }
        })
        yesAction.isEnabled = false
        alert?.addAction(yesAction)   // Disabled on alert creation
   
        // 4. Present the alert.
        self.present(alert!, animated: true, completion: nil)
    }

// Test if textField empty ; note that it was created disabled
    @objc func alertTextFieldDidChange(_ sender: UITextField) {
        alert?.actions[0].isEnabled = sender.text!.count > 0
    }


Hope that helps.

Awesome! Thanks, Claude, that's been a great help.

Hi, Claude, I have a question about #selector. I see that it specifically wants an objc method, but I've been playing around and it seems to call methods such as "TextFieldShouldEndEditing", which are not bridged to @objc, without issue. I'm assuming that is probably not that case and it really shouldn't be done?

These are 2 different things :

TextFieldShouldEndEditing is a delegate function you defined. It is linked "naturally" by compiler.


In #selector, you have a func that must be found dynamically (at run time). You have to use a dynamic dispatch.

@objc forces to include in a dynamic dispatch table.



To test where you need, change the setting of @objc inference to false and compile:

Read here to see how to set this:

https://stackoverflow.com/questions/44379348/the-use-of-swift-3-objc-inference-in-swift-4-mode-is-deprecated


If you introduce new methods or variables to a Swift class, marking them as

@objc
exposes them to the Objective-C runtime. This is necessary when you have Objective-C code that uses your Swift class, or, if you are using Objective-C-type features like
Selectors
. For example, the target-action pattern:
button.addTarget(self, action:#selector(didPressButton), for:.touchUpInside)

- Why would I not mark everything

@objc
?

There are negatives that come with marking something as

@objc
:
  • Increased application binary size
  • No function overloading

Thanks, Claude. Someone else introduced me to a way to acheive it by using notification center. Do you know if there are advantages to one over the other? I guess it all depends on the context.
https://gist.github.com/TheCodedSelf/c4f3984dd9fcc015b3ab2f9f60f8ad51?fbclid=IwAR2d9rHhOxLcwemRvLMl-x4wfwwoywjqgHFJ3NQGb7aCqBzufpYCTlEWvy8

I know this post is a little dated but it's exactly what I needed. I've been able to implement however I can't seem to enable the alert button (or disable) in the objc function. It just doesn't do anything;

    @objc func alertTextFieldDidChange(_ sender: UITextField) {
        print("In the alert did change")
        print("Should Save be enabled?  \(sender.text!.count > 0)")
        print("Button title is \(alertController?.actions[0].title)")
        alertController?.actions[0].isEnabled = sender.text!.count > 0
    }

I've confirmed that the notification for text changed is received by function and confirmed that the sender,text.count > 0 is true (or false) so it should be enabling but it's not. I even tried just enabling the button automatically whenever any textChange event received (alertController?.actions[0].isEnabled = true) but that didn't work either. I am using XCode 14.2. I found other examples of people doing it this way as well however they were just using a single action button. Any idea why this button isn't enabling?

How to disable UIAlertController Buttons?
 
 
Q