🍎 Kuba Suder's blog on Mac & iOS development


Advances in UI Data Sources

Categories: UIKit 0 comments Watch the video

Current approach:

UI***ViewDataSource protocol with numberOfSections, numberOfItems and cellForItemAt methods

This works well for static data, but when you need to update the list later, you need to either reload all data, which results in bad UX, or calculate the changes manually, which is complicated and error-prone

The UI and data source must always agree and there’s no single source of truth

New approach:

Diffable data sources

performBatchUpdates()  ⭢  apply()

Snapshot: saved current state of the UI

Uses identifiers instead of index paths

UICollectionViewDiffableDataSource, UITableViewDiffableDataSource, NSCollectionViewDiffableDataSource

Setting up:

dataSource = UICollectionViewDiffableDataSource<…>(collectionView: collectionView) {
  collectionView, indexPath, mountain -> UICollectionViewCell? in
  // basically the same as cellForItemAt

If we use native objects/structs as identifiers, we get them passed here so we don’t need to look them up in an array by index path

Updating data:

Step 1: Create an empty snapshot

let snapshot = NSDiffableDataSourceSnapshot<Section, Mountain>()

Step 2: Fill it with sections and items


Section and item identifiers can be your own hashable types (e.g. an enum for sections)

Step 3: Apply the snapshot

dataSource.apply(snapshot, animatingDifferences: true)

→ it’s safe to call apply() from a background thread (but don’t mix main & background threads)

Alternatively, you can use a snapshot of the existing state:

let snapshot = dataSource.snapshot()

Getting an identifier from an index path in other delegate methods:

let identifier = dataSource.itemIdentifier(for: indexPath)

Leave a comment


This will only be used to display your Gravatar image.


What's the name of the base class of all AppKit and UIKit classes?