Метод делегата textFieldShouldEndEditing запускается несколько раз для одного объекта текстового поля при выполнении экземпляра UIAlertController

У меня есть контроллер представления под названием LoginViewController, который соответствует UITextFieldDelegate и имеет два объекта текстового поля, а именно Email и Password. На текстовое поле Email наложена функция проверки электронной почты, и если проверка не пройдена, сработает экземпляр UIAlertController.

Вот скриншоты сцен и кода, прежде чем я продолжу свой вопрос:

Сцена входа

Войти в сцену с ошибкой

ps: существует множество операторов печати, позволяющих мне понять ход выполнения

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
}

Когда правильно отформатированный адрес электронной почты вводится в текстовое поле Email и фокус перемещается в следующее текстовое поле (Password) либо с помощью следующей клавиши, либо вручную нажав на следующее текстовое поле (Password), следующие цепочки методов делегата происходят, как и ожидалось. (и понял):

console output:

Формат: [имя метода делегата: значение заполнителя текстового поля (+ текстовое значение)]

 textFieldShouldBeginEditing: Email text field
 textFieldDidBeginEditing: Email text field
 textFieldShouldBeginEditing: Password text field
 textFieldShouldEndEditing returning true: Email text field w/ value: [email protected]
 textFieldDidEndEditing: Email text field w/ value: [email protected]
 textFieldDidBeginEditing: Password text field
 email field is filled
 textFieldShouldReturn: Email text field w/ value: [email protected]

Проблема возникает, когда в текстовом поле Email обнаруживается неправильный отформатированный адрес электронной почты. Метод UITextFieldDelegate textFieldShouldEndEditing вызывается три раза вместо одного, поскольку представлен экземпляр UIAlertController.

ps: предупреждение отображается только один раз на экране.

console output: Формат: [имя метода делегата: значение заполнителя текстового поля (+ текстовое значение)]

 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

Основываясь на объяснении из этого потока: "textFieldShouldEndEditing вызывается несколько раз", я понимаю, что фокус вот-вот покинет текстовое поле Email (первое появление метода textFieldShouldEndEditing срабатывает), фокус уже находится на текстовом поле Password, таким образом, получая статус первого респондента. Но, поскольку обнаружена недопустимая электронная почта, отображается контроллер предупреждений, и текстовое поле Password внезапно теряет фокус и, таким образом, также вызывает textFieldShouldEndEditing. Итак, я ожидаю, что textFieldShouldEndEditing сработает только дважды (один из-за текстового поля Email. Другой из-за текстового поля Password) вместо трех раз (все из-за Email текстового поля) следующим образом:

 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

Но это не так. Может ли кто-нибудь просветить, почему мое понимание неверно. Спасибо за любой указанный указатель.


person yohannes    schedule 09.08.2016    source источник


Ответы (1)


Поместите код подтверждения электронной почты в

func textFieldDidEndEditing(textField: UITextField)

вместо

func textFieldShouldEndEditing(textField: UITextField) -> Bool

и перед отображением контроллера предупреждений вы также можете добавить (если хотите)

self.view.endEditing(true)

и при нажатии OK действие, которое вы можете установить

self.emailTextField.becomeFirstResponder()

Надеюсь, что этот подход решит вашу проблему.

person Haripal Wagh    schedule 09.08.2016
comment
Привет, Харипал, я попробовал ваше предложение, но выдает следующую ошибку: Warning: Attempt to present <UIAlertController: 0x7fdbb060b160> on <Wlkthru.LoginViewController: 0x7fdbb05a7190> which is already presenting (null). Единственный известный мне способ устранить эту ошибку — проверить, равно ли presentedViewController нулю. Если это ноль, создайте контроллер предупреждений и действие, а затем представьте его. Затем ошибка исчезла. Итак, я вернулся к исходной точке. - person yohannes; 10.08.2016
comment
Я использовал тот же подход для достижения того, чего вы пытаетесь достичь... Используйте приведенный ниже код для представления контроллера предупреждений. - person Haripal Wagh; 11.08.2016