Table View Cell Button Navigation

Problem Design and implement a screen containing a table view (list) where every cell holds a button, and tapping that button navigates to a new screen carrying the tapped row's context.

Requirements

  • configure(with: RowModel, at: IndexPath) on the cell — bind data and identity
  • onButtonTap: (() -> Void)? (or delegate: CellDelegate? with didTapButton(in cell: Cell))
  • Controller-side handler: didTapButton(at indexPath: IndexPath) -> push/present the destination screen
  • Correct row association must survive cell reuse and list mutation (insert/delete/reorder)

Core design

  • Custom cell subclass owns the button and exposes a single outbound hook. Two idiomatic options:
    • Closure: cell declares var onButtonTap: (() -> Void)?; the button's action invokes it. In cellForRowAt, the controller assigns a closure capturing the model/index path and performs navigation.
    • Delegate: cell holds a weak delegate; on tap it calls delegate?.didTapButton(in: self), and the controller resolves the row via indexPath(for: cell) — reuse-safe because the index is read at tap time, not capture time.
  • The cell stays dumb: it renders and reports intent. Navigation lives in the controller (or a coordinator/router), so the cell has no knowledge of the destination screen.
  • Explicitly avoid button.tag = indexPath.row — tags break on section-ed lists, reuse, and any mutation of the data source.

Discussion points

  • Retain cycles: closures capturing self strongly leak the controller — capture [weak self]; delegates must be weak var.
  • Cell reuse: reset onButtonTap = nil in prepareForReuse so a recycled cell never fires a stale handler.
  • Stale indices: a captured indexPath goes wrong after a row insert/delete. Capture a stable model ID, or use the delegate form and resolve the index at tap time.
  • Trade-off: closures are terser and colocate the handler with configuration; delegates scale better when a cell emits several distinct events.
  • Extension: pushing this through a coordinator/router keeps the controller free of destination construction and makes navigation unit-testable.
asked …
LeaderboardSalaryAccount