Как отследить изменение текста в UITextField в реальном времени (Swift)
Решение через событие UIControl.Event.editingChanged
Вы абсолютно правы — делегатные методы textFieldDidEndEditing и textFieldShouldReturn не подходят для отслеживания изменений в реальном времени. Правильный способ — использовать событие .editingChanged, которое генерируется при каждом изменении текста (вставка, удаление, замена).
Способ 1: Подключение через Interface Builder (рекомендуется)
Самый простой и наглядный способ — подключить событие в Storyboard или XIB:
- Откройте ваш Storyboard
- Нажмите правой кнопкой мыши на UITextField
- В появившемся меню найдите событие Editing Changed
- Перетащите соединение к вашему ViewController и выберите метод, который будет вызываться
Способ 2: Программное подключение через target-action
Этот способ даёт больше гибкости и подходит, если вы создаёте UI программно. Вот полный рабочий пример:
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var validationIcon: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Настраиваем делегат (оставляем для других методов, если нужно)
emailTextField.delegate = self
// Главное: добавляем target для события editingChanged
emailTextField.addTarget(self,
action: #selector(textFieldDidChange(_:)),
for: .editingChanged)
}
// Этот метод будет вызываться при каждом изменении текста
@objc func textFieldDidChange(_ textField: UITextField) {
validateEmail()
}
func validateEmail() {
guard let email = emailTextField.text else { return }
// Простая, но более надёжная валидация
if !email.isEmpty && email.contains("@") && email.contains(".") {
validationIcon.image = UIImage(systemName: "checkmark.circle.fill")
validationIcon.tintColor = .green
} else {
validationIcon.image = UIImage(systemName: "xmark.circle.fill")
validationIcon.tintColor = .red
}
}
// Делегат можно использовать для других целей, например, скрыть клавиатуру
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Способ 3: Использование уведомлений (для продвинутых случаев)
Если вам нужно отслеживать изменения из разных частей приложения, можно использовать NotificationCenter:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(textDidChangeNotification(_:)),
name: UITextField.textDidChangeNotification,
object: emailTextField
)
}
@objc func textDidChangeNotification(_ notification: Notification) {
validateEmail()
}
// Не забудьте отписаться в deinit
deinit {
NotificationCenter.default.removeObserver(self)
}
Почему это работает?
- .editingChanged — это событие UIControl, которое срабатывает при каждом изменении содержимого текстового поля
- Оно вызывается как при вводе с клавиатуры, так и при программном изменении
textField.text = "..." - Не требует, чтобы поле теряло фокус — реакция мгновенная
Используйте второй способ (target-action) как основной — это стандартный и самый читаемый подход в Swift. Удачи!
<<Альтернатива: Combine и Publisher (iOS 13+)
Если вы используете современные версии iOS (13+), можно применить фреймворк Combine для реактивного отслеживания изменений. Это особенно удобно, если вы уже используете Combine в проекте.
import UIKit
import Combine
class ViewController: UIViewController {
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var validationIcon: UIImageView!
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
// Создаём Publisher для изменений текста
NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: emailTextField)
.compactMap { $0.object as? UITextField }
.map { $0.text ?? "" }
.sink { [weak self] text in
self?.validateEmail(text)
}
.store(in: &cancellables)
}
private func validateEmail(_ email: String) {
if !email.isEmpty && email.contains("@") && email.contains(".") {
validationIcon.image = UIImage(systemName: "checkmark.circle.fill")
validationIcon.tintColor = .green
} else {
validationIcon.image = UIImage(systemName: "xmark.circle.fill")
validationIcon.tintColor = .red
}
}
deinit {
cancellables.removeAll()
}
}
Плюсы Combine подхода:
- Декларативный стиль — легко читать и поддерживать
- Автоматическое управление памятью через
AnyCancellable - Можно легко комбинировать с другими Publisher (например, debounce для поиска)
Минусы:
- Требуется iOS 13+
- Дополнительная зависимость от Combine (хотя он встроенный)
- Может быть избыточным для простых случаев
Выбирайте этот способ, если ваш проект уже использует Combine или вы хотите изучить реактивное программирование. Для простых задач лучше подойдёт target-action из первого ответа.
Ответов пока нет.
Войдите чтобы оставить ответ