Skip to content

UIKit table views, reuse, prefetching, and diffable data

A table view renders a changing linear collection. The model snapshot and the visible rows need one stable identity vocabulary.

Configure by identifier

enum Section { case favorites, notes }
typealias DataSource = UITableViewDiffableDataSource<Section, NoteID>
let registration = UITableView.CellRegistration<UITableViewCell, NoteID> {
[weak self] cell, _, id in
guard let note = self?.notesByID[id] else { return }
var content = cell.defaultContentConfiguration()
content.text = note.title
content.secondaryText = note.body
cell.contentConfiguration = content
}

The closure retrieves current data by ID. It does not trust a stale array offset captured before filtering or reordering.

Apply one snapshot

var snapshot = NSDiffableDataSourceSnapshot<Section, NoteID>()
snapshot.appendSections([.favorites, .notes])
snapshot.appendItems(favoriteIDs, toSection: .favorites)
snapshot.appendItems(otherIDs, toSection: .notes)
dataSource.apply(snapshot, animatingDifferences: true)

Mutate the model first, derive one snapshot, then apply it. Updating the backing array and table rows through separate commands creates invalid-update crashes and identity drift.

Reset and cancel reuse work

Cells replace content, accessories, selection state, and images on every configuration. Prefetch tasks are keyed by note ID and cancelled when rows leave the prefetch window. Completion checks the represented ID before assigning an image.

Prefetching is an optimization. It cannot become the only path that loads required data.

Preserve collection state

Search, refresh, deletion, and grouping reconcile selection and scroll intent. Empty library, no search results, loading, and failure are different states with different recovery.

Validation boundary

Table reuse, snapshot animation, prefetch cancellation, scrolling, selection, performance, and accessibility remain Not verified.

Series navigation

References