iOS Tutorial: Collection View and Diffable Data Source
In this iOS tutorial, you’ll learn how to implement a collection view with UICollectionViewDiffableDataSource and NSDiffableDataSourceSnapshot. By Jordan Osterberg.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
iOS Tutorial: Collection View and Diffable Data Source
20 mins
- Getting Started
- What is UICollectionViewDiffableDataSource?
- Benefits of UICollectionViewDiffableDataSource
- Creating a Diffable Data Source
- Implementing Hashable
- Configuring The Diffable Data Source
- Using NSDiffableDataSourceSnapshot
- Fixing Search
- Multiple Sections
- Option One
- Creating the Section Class
- Adopting the New Section Class
- Fixing Search, Again
- Supplementary Views
- Where to Go From Here?
In iOS 13, Apple introduced a major update to the UICollectionView
API: UICollectionViewDiffableDataSource
. This new API is more flexible and declarative than the complicated, brittle and error-prone UICollectionViewDataSource
API.
In this tutorial, you’ll learn how to:
- Replace the old
UICollectionViewDataSource
with the newUICollectionViewDiffableDataSource
. - Use
NSDiffableDataSourceSnapshot
. - Add sections to the data source.
- Add supplementary views to the data source.
Further, you’ll see how easy it is to animate changes with this new type of data source. I hope you’re excited to get started!
Getting Started
Start by downloading the project materials using the Download Materials button at the top or bottom of this tutorial.
The project, fittingly called RayTube, allows you to browse a collection of RayWenderlich video courses, search for a specific one, and tap it to view more details about it.
First up, open the starter project. Build and run.
You’ll see a list of RayWenderlich videos. Tap a video to see its details. Also, try searching for a specific video by title using the search bar.
At the moment, the filtered videos aren’t animated when you perform a search query.
Obviously, this isn’t ideal. This UI looks like it stutters, which may not be the animation you want. You need to that smooth animation! While adding a diffable data source, you will automagically solve this issue as well.
What is UICollectionViewDiffableDataSource?
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.
UICollectionView
before, check out UICollectionView Tutorial: Getting Started to understand how it works.
The new UICollectionViewDiffableDataSource
abstracts a significant amount of UICollectionViewDataSource
‘s logic. This leaves less room for client code errors when handling collection view’s data source.
Rather than telling the data source how many items to display, you tell it what sections and items to display.
The diffable part of UICollectionViewDiffableDataSource
means that whenever you update the items you’re displaying, the collection view will automatically calculate the difference between the updated collection and the one previously shown. This will in turn cause the collection view to animate the changes, such as updates, insertions and deletions.
Benefits of UICollectionViewDiffableDataSource
Here are three benefits of implementing UICollectionViewDiffableDataSource
:
- Automatic data change animations: Whenever you add, update or delete data, you can get the data change animation automatically.
-
Automatic data synchronization: To utilize collection view’s standard animation without
UICollectionViewDiffableDataSource
, you’d have to manually manage and synchronize data changes between the collection view and the data source. If you have a misalignment in one of the synchronization operations, you’d see an error like this: - Reduced code: Overall, you can write less code and benefit from the collection view’s data change animations and data synchronization.
Smart, right!? So, how do you make use of the new UICollectionViewDiffableDataSource
? More on this next.
Creating a Diffable Data Source
UICollectionViewDiffableDataSource
has two generic types: Section type and item type. If you’ve used collection views before, you should be familiar with the concept of sections and items.
To create your section type, add the following code below videoList
in VideosViewController.swift:
enum Section {
case main
}
Now that you’ve created the Section
enum, it’s time to create the diffable data source.
To keep things concise, create a type alias for the data source. This mitigates the need to write UICollectionViewDiffableDataSource
value types when you need to configure the data source as well as every time you need to reference the same data type.
Below the section type, write the following code to declare a DataSource
type alias:
typealias DataSource = UICollectionViewDiffableDataSource<Section, Video>
Awesome! Build and run.
As it turns out, your video data type needs to conform to Hashable
.
Implementing Hashable
Hashable
allows the diffable data source to perform updates when videos are added, removed or updated. Conformance to the protocol is needed in order to know whether or not two elements are equal to each other.
Open Video.swift. Make Video
adopt Hashable
:
class Video: Hashable {
Next, you need to implement the protocol methods. Add the following code below init(title:thumbnail:lessonCount:link:)
:
// 1
func hash(into hasher: inout Hasher) {
// 2
hasher.combine(id)
}
// 3
static func == (lhs: Video, rhs: Video) -> Bool {
lhs.id == rhs.id
}
Here’s what you did:
- Implemented
hash(into:)
, which hashes the given components. - Added the
id
ofVideo
to the hash. For videos, you only need the ID to know whether two videos are equal. - Implemented the
Equatable
protocol’s==
function, because allHashable
objects must also beEquatable
.
Your project should now be able to build again without any errors.
Configuring The Diffable Data Source
Open VideosViewController.swift. Now that Video
conforms to Hashable
, you can finish creating the diffable data source.
Below viewDidLoad()
, add the following code:
func makeDataSource() -> DataSource {
// 1
let dataSource = DataSource(
collectionView: collectionView,
cellProvider: { (collectionView, indexPath, video) ->
UICollectionViewCell? in
// 2
let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: "VideoCollectionViewCell",
for: indexPath) as? VideoCollectionViewCell
cell?.video = video
return cell
})
return dataSource
}
Here:
- You create a
dataSource
, passing incollectionView
and acellProvider
callback. - Inside the
cellProvider
callback, you return aVideoCollectionViewCell
. The code you write in this function is the same as you’re used to seeing inUICollectionViewDataSource
‘scollectionView(_:cellForItemAt:)
.
Now that you’ve implemented makeDataSource()
you can delete the data source methods under `// MARK: - UICollectionViewDataSource`
. Specifically, delete the following two methods:
collectionView(_: numberOfItemsInSection:)
collectionView(_:cellForItemAt:)
You can delete these methods because the diffable data source automatically handles these functionalities for you.
Next, it’s time to actually use the makeDataSource()
you worked so hard on!
In VideosViewController
, add the following property to the top:
private lazy var dataSource = makeDataSource()
This creates the data source for the collection view. You must mark it lazy
because Swift requires VidoesViewController
to complete initialization before you can call makeDataSource()
.
Finally, inside collectionView(_:didSelectItemAt:)
replace:
let video = videoList[indexPath.row]
…with:
guard let video = dataSource.itemIdentifier(for: indexPath) else {
return
}
This ensures the app retrieves videos directly from the dataSource
. This is important because UICollectionViewDiffableDataSource
might do work in the background that makes videoList
inconsistent with the currently displayed data.
Build and run.
And…nothingness.
Before the collection view can display any cells, you need to tell it what data you’d like to display. This is where snapshots come in!