I have a view controller called LoginViewController
that conforms to UITextFieldDelegate
and have two text field objects namely Email
and Password
. There's an email validation function imposed on the Email
text field and should the validation fails, an instance of UIAlertController
will kick in.
Here's the screenshots of the scenes and the code before I continue with my question:
ps: There are lots of print statement to allow me to understand the flow of execution
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
guard self.validateEmail(self.emailTextField.text!) else {
print("self.presentedViewController: \(self.presentedViewController)")
if self.presentedViewController == nil {
let alertController = UIAlertController(title: "Invalid Email Address", message: "Please try again.", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
}
print("textFieldShouldEndEditing returnin false: \(textField.placeholder!) text field w/ value: \(textField.text!)")
return false
}
print("textFieldShouldEndEditing returning true: \(textField.placeholder!) text field w/ value: \(textField.text!)")
return true
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
print("textFieldShouldBeginEditing: \(textField.placeholder!) text view")
return true
}
func textFieldDidEndEditing(textField: UITextField) {
print("textFieldDidEndEditing: \(textField.placeholder!) text field with value: \(textField.text!)")
}
func textFieldDidBeginEditing(textField: UITextField) {
print("textFieldDidBeginEditing: \(textField.placeholder!) text field")
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
if !(self.emailTextField.text?.isEmpty)! && !(self.passwordTextField.text?.isEmpty)! {
self.emailTextField.resignFirstResponder()
self.passwordTextField.resignFirstResponder()
}
else if !(self.emailTextField.text?.isEmpty)! {
self.passwordTextField.becomeFirstResponder()
}
print("textFieldShouldReturn: \(textField.placeholder!) text field w/ value: \(textField.text!)")
return true
}
When properly formatted email address is entered in the Email
text field and focus is moved to the next text field (Password
) either via the next key or manually tapping on the next text field (Password
), the following chains of delegate methods occurs as expected (and understood):
console output:
Format: [name of delegate method: text field placeholder value (+ text value)]
textFieldShouldBeginEditing: Email text field
textFieldDidBeginEditing: Email text field
textFieldShouldBeginEditing: Password text field
textFieldShouldEndEditing returning true: Email text field w/ value: abc@abc.co
textFieldDidEndEditing: Email text field w/ value: abc@abc.co
textFieldDidBeginEditing: Password text field
email field is filled
textFieldShouldReturn: Email text field w/ value: abc@abc.co
The issue arises when incorrect formatted email address is detected on the Email
text field. The UITextFieldDelegate
method textFieldShouldEndEditing
is invoked three times instead of once as instance of UIAlertController
is presented.
ps: the alert view is only however displayed once on the screen.
console output:
Format: [name of delegate method: text field placeholder value (+ text value)]
textFieldShouldBeginEditing: Email text field
textFieldDidBeginEditing: Email text field
textFieldShouldBeginEditing: Password text field
//1st occurence
self.presentedViewController: nil
textFieldShouldEndEditing returnin false: Email text field w/ value: bob
//2nd occurence
self.presentedViewController: Optional(<UIAlertController: 0x7f9018662df0>)
textFieldShouldEndEditing returnin false: Email text field w/ value: bob
//3rd occurence
self.presentedViewController: Optional(<UIAlertController: 0x7f9018662df0>)
textFieldShouldEndEditing returnin false: Email text field w/ value: bob
Based on the explanation from this so's thread: "textFieldShouldEndEditing called multiple times", my understanding is that as focus is about to leave the Email
text field (the 1st occurence of textFieldShouldEndEditing
method kicked in), focus is already on the Password
text field thus gaining the first responder status. But, because invalid email is detected, an alert controller is presented and Password
text field abruptly loses focus and thus triggers textFieldShouldEndEditing
too. So, I am expecting the textFieldShouldEndEditing
to only get triggered twice (one due to Email
text field. The other due to Password
text field) instead of three times (all due to Email
text field) like this:
textFieldShouldBeginEditing: Email text field
textFieldDidBeginEditing: Email text field
textFieldShouldBeginEditing: Password text field
self.presentedViewController: nil
textFieldShouldEndEditing returnin false: Email text field w/ value: bob
self.presentedViewController: Optional(<UIAlertController: 0x7f9018662df0>)
textFieldShouldEndEditing returnin false: Password text field w/ value: nil
But, that's not the case. Can anyone enlighten why my understanding is not correct. Thanks for any pointer provided.