· 4 min read

Using Diffable Data Source with Collection Views

Using Diffable Data Source with Collection Views

If you have some experience with iOS app development, you should be very familiar with the data source protocols such as UICollectionViewDataSource and UITableViewDataSource. Traditionally, to populate data in a collection view, you have to adopt the UICollectionViewDataSource protocol and implement two required methods:

  • func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
  • func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

Since the release of iOS 13, Apple introduced a new approach known as Diffable Data Sources to manage data for a collection view. This approach replaces the old approach which uses the UICollectionViewDataSource protocol. You no longer need to deal with all the methods mentioned above. Instead, you have to create a UICollectionViewDiffableDataSource object to configure the collection view cell. And, you need to provide a NSDiffableDataSourceSnapshot object to tell the collection what data to display.

To fill a collection view with data using the new approach, here are the procedures:

  1. Connect a diffable data source to your collection view.
  2. Implement a cell provider to configure the cell of your collection view.
  3. Generate the current state of the data
  4. Display the data in the UI

In this tutorial, we will walk you through the usage of UICollectionViewDiffableDataSource and see how you can apply this new approach to manage a collection view’s data.

The Demo Project

Before you begin, please download this starter project. I have already prepared the images and the storyboard for you. In Main.storyboard, you should find a UICollectionViewController with a prototype cell that contains an image view and a label.

diffable-data-source-storyboard

The cell is associated with IconCollectionViewCell. In the IconCollectionViewController.swift file, you will find the iconSet variable, which stores the demo data. What we are going to do is to fill the collection view with images and create a grid UI using diffable data source. The figure below shows the final deliverable.

diffable-data-source-collection-view

Using Diffable Data Source

To use the UICollectionDiffableDataSource object, we need to specify the number of sections and the cell configuration of each section. For this demo app, we only have a single section. Let’s declare an enum variable in the IconCollectionViewController class like this:

enum Section {
    case all
}

We use enum to define a new Section type. In the enumeration, it only has one case because the table has a single section. I name the case all, which means all records. But you can actually name it to whatever name you like. Anyway, let’s keep it to all.

Now that we have defined the section, the next step is to create an instance of UICollectionViewDiffableDataSource. We will write a new function called configureDataSource() for this purpose. Insert the following code in the class:

func configureDataSource() -> UICollectionViewDiffableDataSource<Section, Icon> {

    let dataSource = UICollectionViewDiffableDataSource<Section, Icon>(collectionView: collectionView) { (collectionView, indexPath, icon) -> UICollectionViewCell? in

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! IconCollectionViewCell
        cell.iconImageView.image = UIImage(named: icon.name)
        cell.iconPriceLabel.text = "$\(icon.price)"

        return cell
    }

    return dataSource
}

In the code above, the function returns an instance of UICollectionViewDiffableDataSource<Section, Icon>, which comes with a closure that creates and configures each of the cells for the collection view. This closure is referred as the cell provider.

What’s Section and Icon here?

UICollectionViewDiffableDataSource is a generic object which is capable to handle different types of section and item of a collection view. The type Section and Icon inside the angle bracket indicated that we use the Section type for the section. Since we are going to display the data stored in iconSet, the Icon type is used for the cell data.

Meanwhile, you should notice an error indicating that the type Icon doesn’t conform to protocol Hashable. To use UICollectionViewDiffableDataSource, the type of the item (i.e. Icon) is required to conform the Hashable protocol. Switch over to Icon.swift and declare the conformance like this:

struct Icon: Hashable {
  .
  .
  .
}

Now that we have created the function for configuring the data source, declare the following variable in IconCollectionViewController to use it:

lazy var dataSource = configureDataSource()

Furthermore, we need to connect this data source with the collection view. Insert the following code in the viewDidLoad() method:

collectionView.dataSource = dataSource

You may wonder why we add a modifier lazy before the variable declaration. If you try to omit the lazy keyword, Xcode will show you the following message:

“Cannot use instance member ‘configureDataSource’ within property initializer; property initializers run before ‘self’ is available”

In this case, you must declare the variable with the lazy modifier because its initial value cannot be retrieved until after the instance initialization completes.

We still have one more step to implement before the data shows up in the collection view. Create a new method called updateSnapshot like this:

func updateSnapshot(animatingChange: Bool = false) {

    // Create a snapshot and populate the data
    var snapshot = NSDiffableDataSourceSnapshot<Section, Icon>()
    snapshot.appendSections([.all])
    snapshot.appendItems(iconSet, toSection: .all)

    dataSource.apply(snapshot, animatingDifferences: false)
}

To display the data in the collection view, the final step is to create a snapshot of the data. The snapshot is an instance of NSDiffableDataSourceSnapshot. In the code above, we created an empty snapshot using the section identifier type Section and item identifier type Icon.

With the empty snapshot, we call appendSections to add a section to the snapshot. Then we call appendItems to add all items in the iconSet array to the .all section. Lastly, we apply the snapshot to the data source.

Don’t forget to insert the following line of code in the viewDidLoad() method to make the call:

updateSnapshot()

Now compile and run the app using the iPhone 12/12 Pro simulator. You should have a grid-based Icon Store app like this.

Summary

That’s it! You’ve successfully built a collection view using Diffable Data Source. As you can see, the API is very simple to use and make it easier to manage data update. This is the preferred way to work with data in both collection views and table views. If you are building a new app that makes use of table view/collection view, try to use diffable data source to build the views.

Do you use diffable data source to work with table view or collection view? Or do you still stick with the UICollectionViewDataSource and UITableViewDataSource protocol? Please feel free to leave us comment.

Read next