The Startup
Published in

The Startup

Creating a Reusable UICollectionViewDiffableDataSource Implementation Using MVVM

In this article, we’re going to create a generic and reusable implementation of UICollectionViewDiffableDataSource in MVVM. Hope you’re excited!

Photo by ian dooley on Unsplash

Short Background

UICollectionViewDiffableDataSource is a declarative API for UICollectionView data source released by Apple in iOS 13.
It sets an alternative to the old UICollectionViewDataSource — which provides us with delegate methods to determine the number of sections & cells and cell configuration based on our data set, and methods to remove and insert cells into the collection view. This approach isn’t always safe as things can often go wrong on our side; the data may not always be there at the collection view’s index path or we can miscalculate the ranges when inserting or removing cells at an index path.
Apple figured this out and introduced the diffable data source — an API that manages cell creation, insertion, order and deletion for us based on a snapshot — NSDiffableDataSourceSnapshot which we just provide with sections and items.

In this article, we will look at a simple approach to making a generic and nicely reusable model of UICollectionViewDiffableDataSource in MVVM.

Note: While we are working with UICollectionView in this article, the process is nearly identical for UITableView using UITableViewDiffableDataSource .

In this example, we will build a (very) simple notes app that lets the user compose notes, display them in a collection view and delete them upon tap.
You can download the starter project to follow along :)

In order to be as efficient as possible and create as little number of abstractions as we can, let’s start by defining a protocol named Providable that our UICollectionViewCell subclasses will adopt — in this case NoteCell.

- Note that the ProvidedItem associated type needs to conform to Hashable in order to work with diffable data sources.
- You can set Providable to be bound to UICollectionViewCell if you want, which is more compiler-friendly, but I find it to be useful in other use cases as well :)

In our NoteCell class, we’re going to conform to the protocol and define the associated type as Note:

Great — now let’s get to the main treat.
In this approach, we’re going to create a superclass to our standard View Model, which will contain all the setup and logic of the data source.
We’re going to begin with creating our CollectionViewModel class.

- We inherit from NSObject to enable our subclass view models to conform to UICollectionViewDelegate later on.
- I am making use here of the Binding class for MVVM (sometimes referred to as Box. You can find the implementation of it here.

As we can see, UICollectionViewDiffableDataSource requires a Section type and an Item type as its generics. For the item, we will simply pass in the ProvidedItem from the CellType . As for the section, I may cover working with mutliple sections in a future article, but for now and for simplicity sake we will define a single section — main . Let’s define it now as a simple enum.

Now, let’s implement some of the setup logic of the data source.

What we’re doing here is creating our instance of UICollectionViewDiffableDataSource (that we typealiased as DataSource) and providing its CellProvider closure with our implemented function — cellProvider(_:indexPath:item:).

It’s time for some actual logic, isn’t it?
We now have everything in place to add our main logic methods — add(_:) , remove(_:) and update() to our CollectionViewModel superclass.

This is basically where the magic happens.

  • In the update() method, we are creating a snapshot with our data set. When we call dataSource.apply(), the data source compares the new snapshot to the current one the updates any changes. Since NSDiffableDataSourceSnapshot is a struct (i.e. Value Type) the comparison process is as lightweight and efficient as it gets.
  • The add(_:) method appends a new Item object to the data set and updates.
  • The remove(_:) method removes any item from the data set that matches the provided parameter and updates. This functionality is enabled since our item conforms to Hashable, which in turn inherits from Equatable.

That is our logic implemented for now, but remember that NSDiffableDataSourceSnapshot has much more functionality available for you like reordering cells and sections, inserting, deleting and more. See the documentation

Let’s proceed to connect all the pieces together.
We’re going to inherit from CollectionViewModel in our LibraryViewModel class with our cell type of NoteCell, and conform to UICollectionViewDelegate to implement collectionView(_:didSelectItemAt:) for deleting items.

That is really all there is to it in our view model, now let’s wrap it up in our LibraryViewController.

In the above code we first inject the data source from the factorial method from our CollectionViewModel class.
In line 31 I call the add(_:) method when receiving a new note from the publisher (as I mentioned in the comment, any communication pattern will do just fine).

And that’s it!

I really do hope you enjoyed and took something from this article :)
You can clone (or download) the full project at this link.

Have a great week and an optimistic remainder of 2020!

Photo by Quino Al on Unsplash

--

--

--

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +756K followers.

Recommended from Medium

Swift: filter dictionary

Background Modes in iOS

How to use dark mode in simulator iOS 13?

SwiftUI Beginner’s Notes 1

The Most Admired iOS App Development Trends in 2021

Decommission APIs used by old versions of your mobile app

Create an Apple Health API With Shortcuts and Firebase

The beauty of the Swift programming language with newbie

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Eilon Krauthammer

Eilon Krauthammer

iOS Engineer. I love creating and learning.

More from Medium

Handling dynamic JSON value using Decodable

Design an APP Routing(updating. . .)

Graph — Swift

Map, CompactMap, and FlatMap in Swift