iOS
Swift
UITextField
text change event
iOS development

UITextField text change event

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Detecting text changes in a UITextField is a common requirement for validation, live search, and enabling or disabling buttons. UIKit gives you several ways to do it, and the right choice depends on whether you want to react after the text changes or decide whether a change should be allowed at all.

The Simplest Option: .editingChanged

For most screens, target-action on .editingChanged is the cleanest approach. It fires after the field's text has been updated, which makes it ideal for live validation and UI refreshes.

swift
1import UIKit
2
3final class LoginViewController: UIViewController {
4    private let emailField = UITextField()
5    private let submitButton = UIButton(type: .system)
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        emailField.addTarget(self,
10                             action: #selector(textDidChange(_:)),
11                             for: .editingChanged)
12    }
13
14    @objc private func textDidChange(_ textField: UITextField) {
15        let text = textField.text ?? ""
16        submitButton.isEnabled = text.contains("@")
17    }
18}

This approach is simple because the updated text is already available on the field. You do not have to calculate it manually from a range and replacement string.

Use the Delegate When You Need Control

If you need to reject input before it is applied, use the delegate method textField(_:shouldChangeCharactersIn:replacementString:). This is useful for input masks, length limits, and character filtering.

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

Notice that this method runs before the field updates. If you want the future value, you have to compute it yourself as shown above.

Use Notifications When Another Object Cares

Sometimes the text field owner is not the component that needs to react. In that case, observing UITextField.textDidChangeNotification can be a reasonable choice.

swift
1import UIKit
2
3final class ObserverViewController: UIViewController {
4    private let searchField = UITextField()
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8        NotificationCenter.default.addObserver(
9            self,
10            selector: #selector(handleChange(_:)),
11            name: UITextField.textDidChangeNotification,
12            object: searchField
13        )
14    }
15
16    @objc private func handleChange(_ notification: Notification) {
17        guard let field = notification.object as? UITextField else { return }
18        print(field.text ?? "")
19    }
20
21    deinit {
22        NotificationCenter.default.removeObserver(self)
23    }
24}

This pattern is most useful when you are coordinating behavior across objects. If the view controller already owns the field, target-action is usually simpler.

Choosing the Right Hook

A practical rule is:

  • use .editingChanged for normal live updates
  • use the delegate when you must approve or reject edits
  • use notifications when an outside observer needs to listen

Keeping those use cases separate makes text-input code easier to read. It also avoids writing delegate code when the simpler control event would have been enough.

Common Pitfalls

  • Using the delegate when .editingChanged would be simpler.
  • Forgetting that the delegate method sees the proposed change before it is applied.
  • Reading textField.text inside shouldChangeCharactersIn and assuming it is already updated.
  • Adding notification observers and never removing them in longer-lived objects.
  • Mixing validation logic across target-action, delegates, and notifications without a clear reason.

Summary

  • '.editingChanged is the simplest way to react after the text changes.'
  • Delegate methods are best when you need to allow or reject edits.
  • Notifications help when another object needs to observe changes.
  • Compute the future value manually inside shouldChangeCharactersIn.
  • Pick one primary mechanism for each field to keep input handling predictable.

Course illustration
Course illustration

All Rights Reserved.