Prevent dismissal of UIAlertController
You're correct: if the user can tap a button in your alert, the alert will be dismissed. So you want to prevent the user from tapping the button! It's all just a matter of disabling your UIAlertAction buttons. If an alert action is disabled, the user can't tap it to dismiss.
To combine this with text field validation, use a text field delegate method or action method (configured in the text field's configuration handler when you create it) to enable/disable the UIAlertActions appropriately depending on what text has (or hasn't) been entered.
Here's an example. We created the text field like this:
alert.addTextFieldWithConfigurationHandler {
(tf:UITextField!) in
tf.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)
}
We have a Cancel action and an OK action, and we brought the OK action into the world disabled:
(alert.actions[1] as UIAlertAction).enabled = false
Subsequently, the user can't tap OK unless there is some actual text in the text field:
func textChanged(sender:AnyObject) {
let tf = sender as UITextField
var resp : UIResponder = tf
while !(resp is UIAlertController) { resp = resp.nextResponder() }
let alert = resp as UIAlertController
(alert.actions[1] as UIAlertAction).enabled = (tf.text != "")
}
EDIT Here's the current (Swift 3.0.1 and later) version of the above code:
alert.addTextField { tf in
tf.addTarget(self, action: #selector(self.textChanged), for: .editingChanged)
}
and
alert.actions[1].isEnabled = false
and
@objc func textChanged(_ sender: Any) {
let tf = sender as! UITextField
var resp : UIResponder! = tf
while !(resp is UIAlertController) { resp = resp.next }
let alert = resp as! UIAlertController
alert.actions[1].isEnabled = (tf.text != "")
}
I've simplified matt's answer without the view hierarcy traversing. This is holding the action itself as a weak variable instead. This is a fully working example:
weak var actionToEnable : UIAlertAction?
func showAlert()
{
let titleStr = "title"
let messageStr = "message"
let alert = UIAlertController(title: titleStr, message: messageStr, preferredStyle: UIAlertControllerStyle.Alert)
let placeholderStr = "placeholder"
alert.addTextFieldWithConfigurationHandler({(textField: UITextField) in
textField.placeholder = placeholderStr
textField.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)
})
let cancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (_) -> Void in
})
let action = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: { (_) -> Void in
let textfield = alert.textFields!.first!
//Do what you want with the textfield!
})
alert.addAction(cancel)
alert.addAction(action)
self.actionToEnable = action
action.enabled = false
self.presentViewController(alert, animated: true, completion: nil)
}
func textChanged(sender:UITextField) {
self.actionToEnable?.enabled = (sender.text! == "Validation")
}