Как отследить изменение текста в UITextField в Swift? Событие text change
Решение: Используйте событие UIControl.Event.editingChanged
Проблема в том, что вы полагаетесь на делегат, но для отслеживания изменений текста в реальном времени правильный способ — подписаться на событие .editingChanged от UIControl. UITextField наследуется от UIControl, поэтому вы можете использовать Target-Action механизм.
Вот как это делается:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myTextField: UITextField!
@IBOutlet weak var characterCountLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Подписываемся на событие изменения текста
myTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
}
@objc func textFieldDidChange(_ textField: UITextField) {
// Здесь textField.text уже содержит актуальное значение
guard let text = textField.text else { return }
print("Текст изменился: \(text)")
// Пример: обновляем счётчик символов
characterCountLabel.text = "\(text.count) символов"
// Пример: проверка минимальной длины
if text.count >= 3 {
print("Достаточно символов")
}
}
}
Почему это работает?
.editingChangedсрабатывает каждый раз, когда содержимое текстового поля изменяется: при вводе, удалении, вставке из буфера обмена или при использовании автозамены.- В момент вызова метода текст уже обновлён, поэтому
textField.textсодержит актуальное значение. - Не нужно устанавливать делегат — это отдельный механизм, не конфликтующий с делегатом.
Если вам нужен и делегат, и событие
Вы можете использовать оба подхода одновременно. Например, делегат для валидации ввода (запрет определённых символов), а событие — для реакции на изменения:
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var myTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
myTextField.delegate = self
myTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
}
// Делегат: запрещаем ввод букв
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let allowedCharacters = CharacterSet.decimalDigits
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet)
}
// Событие: реагируем на изменения
@objc func textFieldDidChange(_ textField: UITextField) {
print("Текущий текст: \(textField.text ?? "")")
}
}
Дополнительные советы
- Не забудьте добавить
@objcперед методом, если используете Swift 4+ (для совместимости с Objective-C runtime). - Если вы создаёте текстовое поле программно, подключите событие после добавления на экран.
- Для отписки от события используйте
removeTarget, но обычно это не требуется, если контроллер живёт вместе с текстовым полем.
Это стандартный и рекомендуемый Apple подход для отслеживания изменений текста в UITextField. Используйте его в своих проектах!
<<Альтернативный подход: Использование Combine (iOS 13+)
Если ваш проект поддерживает iOS 13 или новее, можно использовать реактивный подход с фреймворком Combine. Это особенно удобно, если вы уже используете Combine в проекте или хотите избежать селекторов и @objc:
import UIKit
import Combine
class ViewController: UIViewController {
@IBOutlet weak var myTextField: UITextField!
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
// Подписываемся на Notification от UITextField
NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: myTextField)
.compactMap { ($0.object as? UITextField)?.text }
.sink { text in
print("Текст изменился: \(text)")
// Ваша логика здесь
}
.store(in: &cancellables)
}
}
Этот метод использует системное уведомление UITextField.textDidChangeNotification, которое отправляется каждый раз после изменения текста. Преимущество — чистый код без @objc и делегатов, а также возможность легко комбинировать с другими publisher'ами (например, фильтровать или задерживать обработку с помощью Debounce).
Недостаток: требует импорта Combine и поддержки iOS 13+. Для старых версий используйте первый способ с addTarget.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги