Advances in CollectionView

Reena Prajapati
Mindful Engineering
7 min readNov 13, 2020

In the WWDC-2019 Apple announced a lot of exciting new features and frameworks like SwiftUI, PencilKit Framework, Dark Mode. One of them Apple introduced a new API for managing data sources for UITableView and UICollectionView in a much simpler and safer way for developers to use without building their own diffing solutions. It is called Diffable Data Source.

In this article, We will see about Diffable Data Source for UICollectionView.

Image credits: unsplash

What is a Diffable Data Source?

Before iOS 13, you’d configure a UICollectionView’s data source by adopting UICollectionViewDataSource. This protocol tells the collection view what cell to display, how many cells to display, which section to display the cells in, and so on.

Diffable Data Sources are a replacement of the good old UICollectionViewDataSource protocols and make it easier to migrate changes in your data views.

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

There are new class: UICollectionViewDiffableDataSource for collection views.

Whenever your apps data changes, for example when new data has come in from a remote server the collection view needs to update its views. This can be done by calling reloadData() or performBatchUpdates(_:completion:) on the collection view. You typically want to use performBatchUpdates instead of reloadData as the latter reloads all the data and performBatchUpdates lets you update only the parts of the collection view that should actually change in a single animated operation.

To make this work we need to get the difference between the new data and the current state of the collection view and make sure the changes are applied in the right order in performBatchUpdates. Because this is quite complex it is a common source of bugs. Some times you get the following error:

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

The new UICollectionViewDiffableDataSource takes care of all that for you. It does so through a new class called NSDiffableDataSourceSnapshot, which represents the state of the collection view. To display data in the collection view we simply create a snapshot with the updated data and provide it to the data source through calling its apply(_:animatingDifferences:) method. It will then get the current snapshot which represents the current state of the collection view, diff, and update the UI.

Why choose Diffable Data Source?

Here are the benefits of implementing UICollectionViewDiffableDataSource.

  • Whenever you add, update, or delete data, you can get the data to change animation automatically.
  • Without UICollectionViewDiffableDataSource, you have to manually manage animation and synchronize data changes between collection view and data source. Diffable provide automatic data synsynchronization.

In iOS 14, Apple has built on the foundation of Diffable Data Source with two new features: Section Snashots and first-class Reordering Support. Section Snapshots encapsulates the data for a single section in a UICollectionView. There are two reasons for this enhancement. First, to allow data sources to be more composable into section sized chunks. And second, to allow modeling of hierarchical data which is needed to support rendering outline style UIs.

Image credits: mememaker.net

Let’s start the implementation of Diffable Data Source with section snapshot and see how to add snapshots to data sources.

Before we start working on the collection view, we must first get ready with our data model. Let’s go ahead and create a Symbol struct which consists of a title and symbol constant. Prepare array for list and outline section.

Define Section Identifier Type

We’ll first create a section enum to describe three sections.

Define Item Identifier Type

We create a struct Item which represents the data we are going to display in the collection view. We use a UUID for calculating the hash value.

Make sure to confirm the Item struct to the Hashable protocol because the diffable data source that we are going to use requires unique hash values of the item identifiers. If you don’t have an idea about hashable then check this link.

Each of your sections and items must have unique identifiers that conform to the Hashable protocol.

Creating Diffable Data Source

UICollectionViewDiffableDataSource has two generic types. Let’s define a UICollectionViewDiffableDataSource instance variable with Section as the Section identifier type and Item as the item identifier type.

Configuration a Collection View Layout

In iOS 14, Apple has introduced a list layout in UICollectionView with various appearances. Here, We create three layouts for each section.

Let’s see the above code one by one

  1. Implemented closure with section index and collection view layout configuration and return NSCollectionLayoutSection
  2. Checked section index raw value in Section enum
  3. Created collection layout for the grid section with layout group and section. If you no have an idea about the layout group and section, then you can check from here

4. Created a list style layout for the list section with insetGroup appearance.

5. Created a list style layout for the outline section with a plain appearance.

Define How Data Is Shown Using Cell Registration

Next, we will use UICollectionView.CellRegistration API introduced in iOS 14 to create a cell registration that defines how data should be shown in a cell. We do cell registration for the grid section.

Here, we have created a cell registration for cells of type UICollectionViewCell and data items of type Item.

  1. We have created cell registration that defines how data should be shown in a cell.
  2. Defined how data should be shown using default content configuration.
  3. After that, we have assigned the default content configuration to the cell.
  4. A created instance of UIBackgroundConfiguration and updated background configuration then assign to cell backgroundConfiguration property.

Same as grid cell registration, we will define cell registration for the list and outline section. Apple introduced a new UICollectionViewCell subclass called UICollectionViewListCell. This new cell class allows us to implement several tableviewcell-like principles, including swipe actions.

Here, we created a cell registration for cells of type UICollectionViewListCell and data items of type Item.

Now Let’s create cell registration for the outline header cell and outline sub-item cell. We add OutlineDisclosure accessories to our collection view cells to make expandable.

Accessories can be assigned to cells by creating an array of UICellAccessory objects and assigning them to the accessories property of the cell.

CellRegistration API eliminates the extra step of registering a cell class or nib to associate it with a re-use identifier. How cool is that?

Image credits: LowGif

Implementing Diffable Data Source

Create a data source by passing in our collection view and implementing a cell provider closure. Doing this will connect the data source with our collection view.

Inside the cell provider closure, we dequeue a reusable cell using the cell registration for each section that we created previously. Note that we no longer need to use a cell reuse identifier in order to dequeue a reusable cell.

Create and Apply Snapshot to Data Source

NSDiffableDataSourceSnapshot stores your sections and items, which the diffable data source references to understand how many sections and cells to display. Data source applies the snapshot, animating the UI updates between the previous state and the new state represented in the snapshot.

  1. We created instances of NSDiffableDataSourceSectionSnapshot set item identifier type correctly and then appended an array of grid items to snapshot. Applied snapshot to datasource for a particular section.
  2. Same as grid snapshot, created snapshot for list section and applied to datasource.
  3. Created snapshot for outline section, through for in loop created header outlineItem and appended as a parent to snapshot. Then created an array of sub outlineItem and appended as children of outlineItem.
  4. After that, we have applied an outline snapshot to dataSource by using the Apply() method to show data on Collection View.

Implementing Trailing Swipe Action

We can add both leading and trailing swipe actions to a cell by assigning a UISwipeActionsConfigurationProvider instance to the collection view’s UICollectionLayoutListConfiguration object’s leadingSwipeActionsConfigurationProvider and trailingSwipeActionsConfigurationProvider properties. This swipe action provider is expected to return an instance of UISwipeActionsConfiguration. A UISwipeActionsConfiguration is created using an array of one or more UIContextualAction instances.

We added trailing swipe action configuration provider to layout list configuration and got the model for the given index path from the data source.

  1. Initialized UIContextualAction with style, title, and handler. You can customize the icon, title, and background color of a contextual icon as needed.
  2. Created a UIContextualAction handler to perform delete action clicked on the delete button. Passed action handler on UIContextualAction Initializer. Inside handler closure got a snapshot of the data source. Using snapshot deleteItems(:) method deleted particular cell item and then updated snapshot applied to the data source.

Let’s run the app and see how to look UI.

Conclusion

We have seen many new APIs which are introduced by Apple in WWDC 20. We can easily implement expandable in collection view and list in the collection view. I hope you have enjoyed this article.

If you have any queries or questions then you can comment here.

You can download the source code from the below link.

--

--