How to make UIAlertController modal in iOS 9.3?

How to make UIAlertController modal in iOS 9.3? The dialog box comes up, looks right and works correctly, but the app doesn't wait for an answer. I'm using #present(_,animated:,completion:) to bring it up. Even the completion block runs before the user can do anything. There is some API from versions long after 9.3 that might help if I was targeting later versions, but I'm not. I have read a bunch of articles on the net: they all say this easy, and it is easy, but it isn't modal.

Accepted Reply

The alert completion block is run as soon as alert has been displayed, not waiting for user answer.


You need to put actions that require user interaction in the UIAlertAction handlers.


Here is an example of an alert, with request for text entry for a name. We wait for entry validated to close the alertCalled when tapping a button.


    @objc func alertTextFieldDidChange(_ sender: UITextField) {

     alert?.actions[0].isEnabled = sender.text!.count > 0
    }

    @IBAction func testAlert(_ sender: Any) {
   
        //1. Create the alert controller.
        alert = UIAlertController(title: "Recherche de la Ville", message: "Nom de la ville ", preferredStyle: .alert)
      
        //2. Add the text field.
        alert?.addTextField(configurationHandler: { (textField) -> Void in
            textField.placeholder = ""
            textField.keyboardType = UIKeyboardType.emailAddress 
          // alertTextFieldDidChange activate searchButton
            textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
        })
      
        //3. Grab the value from the text field.
        let yesAction = UIAlertAction(title: "Search", style: .default, handler: { (action) -> Void in
            let textField = self.alert?.textFields![0]
            if textField?.text! == "" {
                print("empty")
            } else {
                print("not empty", textField?.text! ?? "")
            }
        })
        yesAction.isEnabled = false
        alert?.addAction(yesAction)
      
        // 4. Present the alert.
        self.present(alert!, animated: true, completion: nil)
      
    }

If you replace line 32 by

     self.present(alert!, animated: true, completion: { print("fired immediately") })


You will see that completion block is executed before any user interaction

Replies

The alert completion block is run as soon as alert has been displayed, not waiting for user answer.


You need to put actions that require user interaction in the UIAlertAction handlers.


Here is an example of an alert, with request for text entry for a name. We wait for entry validated to close the alertCalled when tapping a button.


    @objc func alertTextFieldDidChange(_ sender: UITextField) {

     alert?.actions[0].isEnabled = sender.text!.count > 0
    }

    @IBAction func testAlert(_ sender: Any) {
   
        //1. Create the alert controller.
        alert = UIAlertController(title: "Recherche de la Ville", message: "Nom de la ville ", preferredStyle: .alert)
      
        //2. Add the text field.
        alert?.addTextField(configurationHandler: { (textField) -> Void in
            textField.placeholder = ""
            textField.keyboardType = UIKeyboardType.emailAddress 
          // alertTextFieldDidChange activate searchButton
            textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
        })
      
        //3. Grab the value from the text field.
        let yesAction = UIAlertAction(title: "Search", style: .default, handler: { (action) -> Void in
            let textField = self.alert?.textFields![0]
            if textField?.text! == "" {
                print("empty")
            } else {
                print("not empty", textField?.text! ?? "")
            }
        })
        yesAction.isEnabled = false
        alert?.addAction(yesAction)
      
        // 4. Present the alert.
        self.present(alert!, animated: true, completion: nil)
      
    }

If you replace line 32 by

     self.present(alert!, animated: true, completion: { print("fired immediately") })


You will see that completion block is executed before any user interaction

Strange, and not at all what I want, but good to know. Thank you.

not at all what I want.

So, could you explain in detail what you want ?


There is some API from versions long after 9.3

Which do you think of ?

It is a bit risky to target 9.3 or below. That's now less than 1% of users.

But you could have a test of iOS version and adapt code accordingly. Anyway, please explain what you want precisely.


If you don't need a text entry, just skip this part. The key is to use the handlers for the UIAlertAction (available since iOS 8).


Note: if

preferredStyle: .alert

Then the alert is modal.


As described in UIAlertController doc:

case alert

An alert displayed modally for the app.


What else do you need ?