iOS
Swift
UITableView
UITextField
app development

Having a UITextField in a UITableViewCell

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Putting a UITextField inside a UITableViewCell is a common pattern for forms, settings screens, and editable lists. The main challenge is not placing the text field on screen. It is keeping the text in sync with your data model while cells are reused as the table scrolls.

Use A Custom Cell

Start with a custom cell subclass that owns the text field. Keep the layout and the text-input wiring inside the cell rather than scattering it through the view controller.

swift
1import UIKit
2
3final class FormTextFieldCell: UITableViewCell, UITextFieldDelegate {
4    let textField = UITextField()
5    var onTextChanged: ((String) -> Void)?
6
7    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
8        super.init(style: style, reuseIdentifier: reuseIdentifier)
9
10        textField.translatesAutoresizingMaskIntoConstraints = false
11        textField.borderStyle = .roundedRect
12        textField.delegate = self
13        textField.addTarget(self, action: #selector(textDidChange), for: .editingChanged)
14
15        contentView.addSubview(textField)
16        NSLayoutConstraint.activate([
17            textField.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
18            textField.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),
19            textField.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
20            textField.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16)
21        ])
22    }
23
24    required init?(coder: NSCoder) {
25        fatalError("init(coder:) has not been implemented")
26    }
27
28    @objc private func textDidChange() {
29        onTextChanged?(textField.text ?? "")
30    }
31}

The important part is the callback. The cell should not be the source of truth for the data.

Keep State In The Model, Not The Cell

Because table view cells are reused, storing the text only inside the visible UITextField is a bug waiting to happen. Instead, keep the current value in your backing model.

swift
1final class FormViewController: UITableViewController {
2    var values = ["First name", "Last name", "Email"]
3
4    override func viewDidLoad() {
5        super.viewDidLoad()
6        tableView.register(FormTextFieldCell.self, forCellReuseIdentifier: "FormTextFieldCell")
7    }
8
9    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
10        values.count
11    }
12
13    override func tableView(
14        _ tableView: UITableView,
15        cellForRowAt indexPath: IndexPath
16    ) -> UITableViewCell {
17        guard let cell = tableView.dequeueReusableCell(
18            withIdentifier: "FormTextFieldCell",
19            for: indexPath
20        ) as? FormTextFieldCell else {
21            return UITableViewCell()
22        }
23
24        cell.textField.text = values[indexPath.row]
25        cell.onTextChanged = { [weak self] text in
26            self?.values[indexPath.row] = text
27        }
28
29        return cell
30    }
31}

Now when a cell scrolls off screen and comes back, its text is restored from the model.

Be Careful With Reuse

The most common bugs come from reuse:

  • text appearing in the wrong row
  • callbacks writing to the wrong index path
  • first responder jumping during reloads

If rows can be inserted, deleted, or reordered while editing, storing the row number inside the closure can become fragile. In more dynamic tables, update the model using a stable item identifier rather than the current index path.

Keyboard And Focus Management

When a text field becomes first responder, the keyboard may cover part of the table. A few standard improvements help:

  • use keyboardDismissMode = .onDrag for smoother dismissal
  • scroll the active cell into view if needed
  • avoid full table reloads while the user is editing

For example:

swift
1override func viewDidLoad() {
2    super.viewDidLoad()
3    tableView.keyboardDismissMode = .onDrag
4}

If you call reloadData() after every keystroke, the current cell may be recreated and editing will feel broken. Update only the model unless the UI truly needs a partial row refresh.

Delegate Versus Closure

Closures are convenient for small examples, but a delegate protocol is also fine if you want clearer ownership or if the cell needs to report more than one event.

The design rule stays the same:

  • the cell reports user input
  • the controller or view model owns the form state

That separation keeps reuse manageable.

Common Pitfalls

  • Treating the text field inside the cell as the only copy of the value.
  • Calling reloadData() during editing and disrupting first responder state.
  • Writing changes back to the wrong row after inserts or deletes.
  • Forgetting that reused cells must be fully reconfigured in cellForRowAt.
  • Mixing layout code, input handling, and persistence logic in one oversized view controller.

Summary

  • A UITextField inside a UITableViewCell works well when the cell is custom and reusable.
  • Keep the real value in your model, not only in the visible text field.
  • Reconfigure every reused cell from model state in cellForRowAt.
  • Avoid unnecessary reloads while the user is typing.
  • Use closures or delegates to send text changes upward, but keep data ownership outside the cell.

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.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.