Introduction: Why "Catching" Text Changes is the Foundation?
\n\nImagine: you are writing a recipe search app. The user starts typing "pasta", and your search should trigger instantly, without pressing a button. Or you are making a registration form where you need to highlight the "password too short" error immediately as soon as the user types the third letter.
\n\nIn both cases, you need to know the exact moment when the text in UITextField changed. This question on Stack Overflow has gathered thousands of views — and for good reason. Every iOS developer encounters it sooner or later.
\n\nIn 2025, we have at least 4 ways to solve this problem. Some are veterans, time-tested. Others are fresh approaches that Apple actively promotes. In this article, we will cover all the options, from classic to modern, and I will show you which method to choose for a specific task.
\n\nLet's go! 🚀
\n\nMethod 1. Target-Action: Old School but Works
\n\nThe simplest and most straightforward method that has worked since iOS 2.0. Yes, it's over 15 years old, but it is still relevant.
\n\nThe idea is that UITextField inherits from UIControl, meaning it can generate events. We are interested in the .editingChanged event — it fires on every text change.
Code Example (UIKit + Storyboard or programmatically)
\n\nimport UIKit\n\nclass ViewController: UIViewController {\n\n @IBOutlet weak var searchTextField: UITextField!\n\n override func viewDidLoad() {\n super.viewDidLoad()\n // Add target for text change event\n searchTextField.addTarget(self,\n action: #selector(textFieldDidChange(_:)),\n for: .editingChanged)\n }\n\n @objc func textFieldDidChange(_ textField: UITextField) {\n guard let text = textField.text else { return }\n print("Text changed: \\(text)")\n // Here you can perform search, validation, etc.\n }\n}\n\nPros: minimal code, no need to conform to protocols, works fast.
\nCons: requires using @objc — this is legacy Swift. No fine-grained control (e.g., cannot distinguish text insertion from deletion).
Method 2. UITextFieldDelegate: Control Over Every Character
\n\nIf you need not just to know that the text changed, but to influence the change (block input, format a phone number), then the delegate is your choice.
\n\nThe key method here is textField(_:shouldChangeCharactersIn:replacementString:). It is called before the text actually changes.
Example: Phone Number Formatting
\n\nimport UIKit\n\nclass ViewController: UIViewController, UITextFieldDelegate {\n\n @IBOutlet weak var phoneTextField: UITextField!\n\n override func viewDidLoad() {\n super.viewDidLoad()\n phoneTextField.delegate = self\n }\n\n func textField(_ textField: UITextField,\n shouldChangeCharactersIn range: NSRange,\n replacementString string: String) -> Bool {\n\n // Allow only digits\n let allowedCharacters = CharacterSet.decimalDigits\n let characterSet = CharacterSet(charactersIn: string)\n guard allowedCharacters.isSuperset(of: characterSet) else {\n return false\n }\n\n // Limit length to 10 characters\n let currentText = textField.text ?? ""\n guard let stringRange = Range(range, in: currentText) else { return false }\n let updatedText = currentText.replacingCharacters(in: stringRange, with: string)\n return updatedText.count <= 10\n }\n\n // Additionally: catch the moment when the text has already changed\n func textFieldDidChangeSelection(_ textField: UITextField) {\n print("Text updated: \\(textFi