Diffable Data Source in Swift TableView and CollectionView

Manish Pathak
7 min readMay 12, 2024

--

Why Diffable Data Source ?

From long time in iOS, we have been implementing the collection or tableview data sources. UITableViewDataSource protocol.

Its responsibility is provide to tableView some infos like the number of sections, the number of rows per section, and which cell will be used by tableView on a specific indexPath. Doesn’t matter where the dataSource gets these info, it’s responsible to provide them to tableView.

When we update the tableView removing or updating a row, for example, we need to make sure that dataSource is in sync with tableView, removing this element as well. Otherwise, we’re out of sync, and it can lead to a crash.

The crash message is similar to the message below. In my case, I had a section and three rows. I removed the first row without updating my array of elements, where my dataSource was getting the data.
Terminating app due to uncaught exception

‘NSInternalInconsistencyException’, reason: ‘Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).’

DiffableDataSource solves this problem internally using snapshots.

What is Diffable Data Source ?

A diffable data source provides the behavior you need to manage updates to your table- or collection view’s data and UI in a simple, efficient way. It replaces well-known methods like cellForRowAtIndexPath: and numberOfItemsInSection:.

No performBatchUpdates in DiffableDataSource.

Diffable Data Sources were introduced at WWDC 2019 and are available since iOS 13. They’re a replacement of the good old UICollectionViewDataSource and UITableViewDataSource protocols and make it easier to migrate changes in your data views.

Internal working of DiffableDataSource

A diffable data source is an object that replaces your table view’s current UITableViewDataSource object. This means that it will supply your table view with the number of sections and items it needs to render, and it supplies your table view with the cells it needs to display. To do all this the diffable data source requires a snapshot of your model data. This snapshot contains the sections and items that are used to render your page. Apple refers to these sections and items as identifiers. 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. Let's look at this a little bit more in-depth by exploring the type signatures of both the data source and the snapshot.

First, let’s explore the UITableViewDataSource signature:

class UITableViewDiffableDataSource<SectionIdentifierType, ItemIdentifierType> : NSObject 
where SectionIdentifierType : Hashable, ItemIdentifierType : Hashable

The UITableViewDiffableDataSource 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

struct NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType> 
where SectionIdentifierType : Hashable, ItemIdentifierType : Hashable

The snapshot object is a struct rather than a class, and it has the same generic parameters as the diffable data source it’s applied to. This means that you can’t apply a snapshot with a set of identifiers to a data source with different identifiers and your code will fail to compile.

How to implement DiffableDataSource ?

Before see implementation, let's take an example of using TableviewDataSource —

Using TableviewDataSource

we have simple Payment detail model cell —

we replaced UITableViewDataSource with UITableViewDiffableDataSource. The data source is generic and defines a type for section identifiers and a type for the data that is listed. The cell provider will take this generic as output for the third argument containing the data for which a cell needs to be returned. Data is provided through so-called snapshots: a snapshot of data. This already describes how diffable data sources work. Snapshots of data are compared with each other to determine the minimum amount of changes needed to go from one snapshot to another. The data source is smart enough to calculate the differences and replace code like performBatchUpdates, for example. Diffable Data Sources result in code that is more compact and centralized while at the same time bringing several benefits. In the end, the system takes over a lot of the heavy lifting. To make you understand what this all includes it’s good to list some of the benefits.A few things we did in the above code

  1. Init NsDiffableDataSource. It's a generic type, like the UITableViewDiffableDataSource.
  2. Add the main section and the data in it.
  3. Apply the snapshot on dataSource.
  4. animatedDifferences as false, this parameter as false means that we don’t want the tableView getting animated in this snapshot.
    We don’t want to animate at the first iteration. We want the first elements already in the tableView, not seeing them getting added to it.

Example 2

We create a snapshot and apply the initial snapshot without animation. Note appendSections you should add sections first then add items to these sections. At this point everything working fine , we rendered UI using diffable datasource having complex multiple sections UI. In the next section we will do some experiment to understand diffable datasource more and will try to cover most of the scenarios you will face while building real application

Insert Section with animation

As shown below gif , Initially snapshot has two sections payment breakdown and payment selected. when user tap on Button Payment options section is inserted with left animation as easy . Previously you usually call performBatchUpdates which sometimes leads to a crash when data is not synced with UI data. Now this is maintained by iOS itself which is cool.

As shown below code let’s say when we land on screen we hit API that returns data of two sections, we rendered two sections without animation, Now after we rendered we hit another endpoint that gives data os another section. what we do we insert that section later with animation so the user can feel some data just came . As you can see we first get the data of the old snapshot and then insert section and append items then everything works as in demo

If you not sure , which section is inserting or UI is totally driven from backend , you can create fresh snapshot as well and send it to the apply method it will automatically find diff what changed and do it’s magic, that’s why it is called diffable data source 💃

How DiffableDataSource check the difference between old and new data ?

Diffable data source uses item hash to identify item. For the same item that exists in both old and new snapshots, diffable data source checks if the item changes by doing an “==” operation with its old and new values.

OR

Use HashValue that identify item instantly and == for the property that is using rendering UI, + both hash and == should unique in one snapshot

Summary

A TableView presents data in the form of sections and items, and an app that displays data in a TableView inserts those sections and items into the view. To support these actions, like inserting, deleting, moving, and updating data within a table view.

When populating a table view in an app, you can create a custom data source that adopts the UITableViewDataSource protocol. To keep the information in the table view current, you determine what data changed and perform a batch update based on those changes, a process that requires careful coordination of inserts, deletes, and moves.

To avoid the complexity of that process, the sample app uses a UITableViewDiffableDataSource object. A diffable data source stores a list of section and item identifiers, which represents the identity of each section and item contained in a table view. These identifiers are stable, meaning they don’t change. In contrast, a custom data source that conforms to UITableViewDataSource uses indices and index paths, which aren’t stable. They represent the location of sections and items, which can change as the data source adds, removes, and rearranges the contents of a collection view. However, with identifiers a diffable data source can refer to a section or item without knowledge of its location within a table view.

Happy Learning !!!

--

--