DiffableDataSources in TableViews and CollectionViews

The new declarative way of setting up UITableView & UICollectionView

Ilija Mihajlovic
6 min readSep 18, 2022
Photo by the author

At WWDC 2019 a lot of new great UIKitadditions were announced for iOS 13, like compositional layout for collection views or today’s topic diffable data sources for both collection and table views.

They’re a replacement for the good old UICollectionViewDataSource and UITableViewDataSource protocols and make it easier to migrate changes in our data views.

Traditional Approach

The traditional approach for plugging data sources requires conforming to the UITableViewDataSource protocol and implementing the methods numberOfItemsInSection, numberOfSections, cellForItemAt.

This works all fine for simple TableViews and CollectionViews until we need to start updating the rows. For updating, both the approaches, reloadData() and performBatchUpdates(), had their own sets of issues.

While reloadData() would ruin our chances of showing nice animations, performBatchUpdates() and would quickly lead to errors if not handled carefully.

What are Diffable Data Sources?

Diffable data sources mark a shift toward a declarative paradigm by handling mechanisms like synchronization, updating the changes on their own, thereby making things less error-prone and with the new state-driven approach.

By using the diffing tool, diffable data sources take care of updating the table view and collection view rows between the states (current and new).

Like said It replaces well-known methods like cellForRowAtIndexPath: and numberOfItemsInSection:.

The new diffable data source abstracts a significant amount of UICollectionViewDataSource / UITableViewDataSource‘s logic.

Rather than telling the data source how many items to display, we tell it what sections and items to display.

The diffable part of UICollectionViewDiffableDataSource/ UITableViewDiffableDataSource means that whenever we update the items we’re displaying, the collection view or table view will automatically calculate the difference between the updated and the one previously shown. This will cause the collection or the table view to animate the changes, such as updates, insertions, and deletions.

To do all this the diffable data source requires a snapshot of our model data. This snapshot (NSDiffableDataSourceSnapshot) contains the sections and items that are used to render our page. Apple refers to these sections and items as identifiers (ItemIdentifierTyp). The reason for this is that these identifiers must hashable, and the diffable data source uses the hash values for all identifiers to determine what’s changed. After modifying the snapshot, we useapply()to commit the changes which updates the table view UI.

From now we will focus only on UITableView for simplicity purposes, but everything that is said for table views will also apply for UICollectionView likewise.

Set up table view or collection view using Storyboard or Programmatically

We configure the table view in a classical way. The requirements are the same.

Setting Up the Diffable Data Source

UITableViewDiffableDataSource is a generic class that has two types. Both types need to conform to the Hashable protocol:

  1. SectionIdentifierType: representes the sections of the table view or collection view.
  2. ItemIdentifierType: represents the items of a particular section.

Define the Section identifier type

It’s good practice to use an enum which is by default Hashable and have your sections as cases of the enum type

Data is provided through snapshots(NSDiffableDataSourceSnapshot): a snapshot of data. This already describes how diffable data source work. Snapshots of data are compared with each other to determine the minimum amount of changes needed to go from one snapshot to another.

Snapshots don’t rely on index paths for updating items. Instead, there rely on type-safe unique identifiers to identify their sections and items uniquely.

We also use the hash function to define which property of the Item type should be used for hashing the type's uniqueness. In the case below we use the identifier property.

Let’s explore the DataSource class:

The DataSource class has two generic types, one for the section identifier and one for the item. Both are constrained so that whatever type fills the generic type must conform to Hashable.

Using the DataSource subclass we can now update our declaration for the dataSource instance to use this subclass.

  1. cellProvider is a closure that has 3 arguments: a pointer to the tableView, indexPath of the current item and the item itself. This closure returns an optional UITableViewCell. In many ways, this closure is a replacement for the tableView(_:cellForRowAtIndexPath:) method.
  2. Here we add the default row animation to the data source. The default animation is .automatic. Some other options include .fade .top and.bottom.

3. Assign the dataSource to the tableView.

Setting up the snapshot

To update or populate the data source, we simply add the necessary sections and its items on a snapshot instance and apply, update or remove data on it.

We used to do that by implementing methods from the UITableViewDataSource but with new diffable data source we need to do that a little bit differently - we need to create a snapshot (NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>) which is also a generic class, similar to the UITableViewDiffableDataSource.

The basic steps for setting up a snapshot are as follows:

  1. Declare an instance of NSDiffableDataSourceSnapshot which needs to match the section and item type you specified for the data source earlier.
  2. Use the instance methods shuffled() on the elements

3. Append the required sections to the snapshot.

4. Append the items for the section or each section if the table view or collection view has multiple sections.

5. Apply the snapshot to the data source. This step is the required step to update the current snapshot which will render items to the table view or collection view.

Just need remember that types in both snapshot and data source must be the same.

Update or remove data

To update or remove data from the table view, we need to get a hold of the current snapshot which is done by invoking dataSource.snapshot().

To access items that have index path based APIs in diffable data sources, we need to translate the index path to the item identifier in the following way:

dataSource.itemIdentifier(for: indexPath)

The following code snippet removes elements when selected from the UITableView:

With the following line we are getting the current snapshot:

let currentSnapshot = dataSource.snapshot()

A Little reminder:

  1. UITableViewDiffableDataSource
  2. UICollectionViewDiffableDataSource
  3. NSDiffableDataSourceSnapshot

Snapshot:

  1. appendSections(_:) - add sections to the snapshot
  2. appendItems(_:) - add items to the current section
  3. appendItems(_:, toSection:_) - append items to a given section
  4. sectionIdentifiers - get back all the sections
  5. deleteItems(_:) - remove items from the snapshot
  6. indexOfItem - return the index of an item
  7. sectionIdentifier(containingItem: _) - get the section for a given item
  8. insertItems(_:, afterItem: _) - insert a given source item(s) after a destination item
  9. insertItems(_:, beforeItem: _) - insert a given source item(s) before a destination item

Data source:

  1. snapshot()
  2. apply(_, animatingDifferences:)
  3. itemIdentifier(for:) - uses the index path to retrieve the current item
  4. CellProvider — clousure argument on the data source initializer which has 3 arguments: a pointer to table view or collection view, the current index path and the current item

Conclusion

We’ve seen how the diffable data source introduces a whole new way of building data sources for our collection view and table view. Working with collection or table views data that changes over time is much more appealing thanks to the diffable data sources (as well as compositional layouts) and the new way of declarative programming .

If you want to get in touch and by the way, you know a good joke you can connect with me on Twitter or Linkedin.

That’s it for this one. I hope you enjoyed reading it.😄 🙌

--

--

Ilija Mihajlovic

Lead ITSM Consultant, and computer science graduate, with a passion for AI.