UITextField text change event: Catching Every Keystroke Correctly

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

UITextField text change event: Every Character Counts

\n\n

Imagine: you're writing a notes app, a catalog search, or a messenger. The user just starts typing in a UITextField, and you already need to react — highlight suggestions, count remaining characters, or send a request to the server. How do you catch that exact moment when the text changes? A question that plagues beginners and even experienced iOS developers. On Stack Overflow, the topic UITextField text change event has gathered thousands of views — and for good reason.

\n\n

In iOS development, there are at least three working approaches. Choosing the wrong one could cost you bugs, memory leaks, or an extra 100 lines of code. Today, we'll break down all the ways to track text changes in UITextField: from the classic delegate to modern Combine. Let's go!

\n\n

Why Isn't Just Pressing a Button Enough?

\n\n

It seems simple, right? The user enters text — presses "Done" or the "Search" button. But modern interfaces require real-time reactions. Here are typical scenarios:

\n
    \n
  • Autocomplete (search as you type) — suggestions appear with every keystroke.
  • \n
  • Live validation — checking an email or phone number without submitting a form.
  • \n
  • Character counter — for example, in a Twitter client, showing how many characters are left until the limit.
  • \n
  • Dynamic search — filtering a list of contacts or products.
  • \n
\n

In all these cases, we need the UITextField text change event. And now the question: how to implement it correctly in Swift?

\n\n

Method 1: UITextFieldDelegate — The Classic Approach

\n\n

The most obvious and perhaps the most popular method. You assign a delegate to your text field and implement the textField(_:shouldChangeCharactersIn:replacementString:) method. But there's a nuance: this method is called before the text actually changes. It asks: "Can I insert this character?"

\n\n

To get the actual text, you need to construct it manually:

\n\n
class ViewController: UIViewController, UITextFieldDelegate {\n    \n    @IBOutlet weak var textField: UITextField!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        textField.delegate = self\n    }\n    \n    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {\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        \n        print("New text: \\(updatedText)")\n        // Here you can update the UI or start a search\n        return true\n    }\n}\n
\n\n

Pros:

\n
    \n
  • Full control over input — you can prohibit inserting certain characters.
  • \n
  • Works on all iOS versions.
  • \n
\n

Cons:

\n
    \n
  • Code is cumbersome for simply "catching a change".
  • \n
  • You need to remember about NSRange and conversion to Range<String.Index>.
  • \n
  • Does not trigger when changing text programmatically with textField.text = "new text".
  • \n
\n\n

This approach is great if you need to validate input (for example, prohibit letters in a phone number field). But for simple change tracking, there are more elegant options.

\n\n

Method 2: Target-Action (UIControl.Event.editingChanged) — Simplicity and Reliability

\n\n

The second method is adding a target and action for the .editingChanged event. It triggers after each text change, and the code looks concise:

\n

Blogs

Book Recommendations