UITextField
iOS
Swift
real-time input
text processing

Getting the Value of a UITextField as keystrokes are entered?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Reading a UITextField as the user types is a common UIKit task for search boxes, live validation, and formatted input. The key detail is choosing the right callback, because some APIs give you the text after the change and others give you the proposed edit before it is applied.

In most apps, editingChanged is the simplest solution. When you need to inspect or reject the new text before it appears, use the delegate method that receives the replacement range and string.

Use editingChanged for Live Updates

The easiest way to get the current value after each keystroke is to listen for the .editingChanged control event.

swift
1import UIKit
2
3final class ViewController: UIViewController {
4    private let nameField = UITextField()
5    private let statusLabel = UILabel()
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9
10        nameField.borderStyle = .roundedRect
11        nameField.placeholder = "Type your name"
12        nameField.addTarget(self, action: #selector(textDidChange(_:)), for: .editingChanged)
13    }
14
15    @objc private func textDidChange(_ textField: UITextField) {
16        let currentText = textField.text ?? ""
17        statusLabel.text = "Current value: \(currentText)"
18        print(currentText)
19    }
20}

This callback runs after UIKit updates the field’s text, so textField.text already contains the latest value. That makes it ideal for:

  • enabling or disabling a button
  • filtering a table view
  • showing character counts
  • running lightweight validation

For many screens, this is all you need.

Use the Delegate When You Need the Proposed Value

If you need to know what the text will become before the change is committed, implement UITextFieldDelegate and use textField(_:shouldChangeCharactersIn:replacementString:).

swift
1import UIKit
2
3final class ViewController: UIViewController, UITextFieldDelegate {
4    private let codeField = UITextField()
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8        codeField.delegate = self
9    }
10
11    func textField(
12        _ textField: UITextField,
13        shouldChangeCharactersIn range: NSRange,
14        replacementString string: String
15    ) -> Bool {
16        let current = textField.text ?? ""
17        guard let textRange = Range(range, in: current) else {
18            return false
19        }
20
21        let updated = current.replacingCharacters(in: textRange, with: string)
22        print("Next value:", updated)
23
24        return updated.count <= 6
25    }
26}

This method is different from .editingChanged in an important way: textField.text still contains the old value. You must compute the updated string yourself from the current text, replacement range, and replacement string.

Use this delegate method when you want to:

  • reject invalid characters
  • enforce a maximum length
  • apply custom formatting rules
  • inspect paste operations before accepting them

Debounce Expensive Reactions

Live typing handlers should stay fast. If every keystroke triggers a network request or expensive computation, debounce the work so it runs only after the user pauses briefly.

swift
1import UIKit
2
3final class SearchViewController: UIViewController {
4    private let searchField = UITextField()
5    private var pendingSearch: DispatchWorkItem?
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        searchField.addTarget(self, action: #selector(searchTextChanged(_:)), for: .editingChanged)
10    }
11
12    @objc private func searchTextChanged(_ textField: UITextField) {
13        let query = textField.text ?? ""
14
15        pendingSearch?.cancel()
16
17        let workItem = DispatchWorkItem { [weak self] in
18            self?.performSearch(query: query)
19        }
20
21        pendingSearch = workItem
22        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: workItem)
23    }
24
25    private func performSearch(query: String) {
26        print("Searching for:", query)
27    }
28}

This pattern improves responsiveness and reduces unnecessary work. It is especially useful for auto-complete fields and server-backed search.

Pick the Right Hook

Both APIs are valid, but they solve slightly different problems. .editingChanged is the best default when you want the current visible text. The delegate method is better when you need control over whether the change should happen at all.

UIKit also offers textFieldDidChangeSelection(_:), which can fire for cursor movement as well as text edits. That makes it useful in some advanced editors, but it is not usually the cleanest callback for ordinary “value changed” logic.

Common Pitfalls

The most common mistake is reading textField.text inside shouldChangeCharactersIn and assuming it already contains the new text. It does not. Build the candidate string yourself if you need the post-edit value.

Another issue is doing heavy work directly on every keystroke. Slow validation, repeated layout work, or network requests can make typing feel laggy. Debounce or move heavier tasks off the hot path.

It is also easy to create duplicated logic by mixing target-action and delegate code for the same field without a clear reason. If possible, pick one mechanism as the primary source of truth for that specific behavior.

Finally, remember that optional text values matter. UITextField.text is optional, so defaulting with ?? "" keeps your code predictable.

Summary

  • Use .editingChanged when you want the text field’s current value after each keystroke.
  • Use shouldChangeCharactersIn when you need to inspect or reject a proposed edit before it is applied.
  • Compute the updated string manually inside delegate methods because textField.text still holds the old value.
  • Debounce expensive search or validation work so typing stays responsive.
  • Keep input logic simple by choosing one primary callback style for each use case.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.