Set up a UITableViewDiffableDataSource with a snapshot
Replace a classic cellForRowAt table with a diffable data source. Given a Section enum and a list of Item values, build the data source and apply an initial snapshot so the rows appear.
Constraints:
- Use
UITableViewDiffableDataSourcewith a cell-provider closure. - Apply the items through an
NSDiffableDataSourceSnapshot, notreloadData.
enum Section { case main }
var dataSource: UITableViewDiffableDataSource<Section, Item>!
func configureDataSource(_ tableView: UITableView, items: [Item]) {
// your code here
}
Write the implementation.
Create the data source with a cell-provider closure per Item. Make an NSDiffableDataSourceSnapshot, appendSections([.main]), appendItems(items), then dataSource.apply(snapshot). Unlike reloadData, it animates only the changed rows.
- ✗Calling
reloadDatainstead of applying a snapshot - ✗Forgetting
appendSectionsbeforeappendItems - ✗Thinking diffable data sources are collection-view only
- →How does
apply(_:animatingDifferences:)decide the row animations? - →Why must
ItembeHashablefor the diff to work?
The data source describes cells through a cell-provider, and data arrives as a snapshot:
func configureDataSource(_ tableView: UITableView, items: [Item]) {
dataSource = UITableViewDiffableDataSource<Section, Item>(tableView: tableView) {
table, indexPath, item in
let cell = table.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = item.title
return cell
}
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.main])
snapshot.appendItems(items)
dataSource.apply(snapshot, animatingDifferences: true)
}
Each later apply of a new snapshot diffs the old and new state by the Hashable identity of Item and animates only inserts, deletes, and moves — no manual insertRows/deleteRows and none of the index desyncs that reloadData invites when the backing array mutates.