UIAlertController and input validation

Posted on

Problem

I’m refactoring some “old” Swift code using deprecated UIAlertView and delegates.

I have a UIAlertController with an input textfield inside (and two buttons, OK and CANCEL). The user should insert his email address, then I should validate it anytime he enters a character: when the mail address is valid, the UIAlertController button is enabled, else is disabled.

I got this code perfectly working but for some reason I’m not very happy with this solution. Is there something you would change?

var alertTextField: UITextField!

func textFieldDidChange(){

    if let e = alertTextField.text {
        let alertButton = alertController.actions[0]
        alertButton.isEnabled = !Utils.isValidEmail(testStr: e) ? false : true
    }
}

var alertController = UIAlertController(title: "Insert your email", message: "message", preferredStyle: .alert)


@IBAction func passwordForgot(_ sender: Any) {

    let ok = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
        print("Ok Button was Pressed")
    })
    ok.isEnabled = false

    let cancel = UIAlertAction(title: "Cancel", style: .cancel) { (action) -> Void in
        print("Cancel Button was Pressed")
    }

    alertController.addAction(ok)
    alertController.addAction(cancel)

    alertController.addTextField { (textField) -> Void in
        self.alertTextField = textField
        self.alertTextField?.placeholder = "mail"
        textField.addTarget(self, action: #selector(self.textFieldDidChange), for: UIControlEvents.editingChanged)
    }

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

}

Solution

I would change this:

alertButton.isEnabled = !Utils.isValidEmail(testStr: e) ? false : true

to this one:

alertButton.isEnabled = Utils.isValidEmail(testStr: e)

The aspect of it that I’d change is having to store the alertController as a property. This adds state to your class that will be stale when the alert is done unless you add more code to clear it. And you can get it from somewhere else.

Here’s another way to implement the textFieldDidChange method that doesn’t require the state:

@objc func textFieldDidChange(_ sender: UITextField) {
    guard let alertController = presentedViewController as? UIAlertController else {
        return
    }

    guard let alertButton = alertController.actions[0] else {
        return
    }

    if let e = sender.text {
        alertButton.isEnabled = Utils.isValidEmail(testStr: e)
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *