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!
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
UICollectionViewin this article, the process is nearly identical for
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
- Note that the
ProvidedItemassociated type needs to conform to
Hashablein order to work with diffable data sources.
- You can set
Providableto be bound to
UICollectionViewCellif you want, which is more compiler-friendly, but I find it to be useful in other use cases as well :)
NoteCell class, we’re going to conform to the protocol and define the associated type as
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
- We inherit from
NSObjectto enable our subclass view models to conform to
- I am making use here of the
Bindingclass 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 —
It’s time for some actual logic, isn’t it?
We now have everything in place to add our main logic methods —
update() to our
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
struct(i.e. Value Type) the comparison process is as lightweight and efficient as it gets.
add(_:)method appends a new
Itemobject to the data set and updates.
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
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
In the above code we first inject the data source from the factorial method from our
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!