How to use DiffableDataSource and still support iOS 12

Introduction

If you make heavy use of tables and collection views, iOS 13 brought something great for you — Diffable Data Source. If you’re not familiar with that, you are more than welcome to read my (excellent!) tutorial about how to implement it in your project.

Anyway, In short — DiffableDataSource is a way to refresh your collections, animated, while all the dirty calculations of insert/delete/update are done for you by UIKit.

Sounds Great, What’s the Catch?

DiffableDataSource requires iOS 13. That’s the problem. Collections (When I say “collection”, I mean UITableView or UICollectionView) are a central component in our app, and you cannot ignore iOS 12 users with just show them something else instead. Implementing DiffableDataSource is too easy and useful to just to wait 1–2 years from now to start using it.

This is why it’s not that simple fall back to “reloadData()”

That’s the intuitive and logical thought — why can’t we just check the iOS version and call reloadData()? After all, users that afraid to upgrade might deserve a lousier experience 🙂

The root of the problem is with the datasource itself.

You see, to use DiffableDataSource, you need to keep the diffable data source as an instance variable.

And when you have a class with a variable that requires iOS 13 — the whole class requires iOS 13!

In other words — you cannot do something like that:

import UIKit

class MyTableViewController: UIViewController {

@available(iOS 13.0, *)

var datasource : UITableViewDiffableDataSource<String, String>?

}

And if the whole class requires iOS 13, it means you need to duplicate your class, sub-classing, or any other bloody solution.

I guess I’ll have to wait for next year…

Don’t go yet! There is a solution, and it’s much simpler than you think –

Mark your datasource variable as “lazy,” and you can limit it to iOS 13.

The reason is that lazy variables are relevant only when you call them. And since you can do a version check on the call itself, you can use the @available operator to limit them.

Let’s see the solution:

import UIKit

class MyTableViewController: UIViewController {

@available(iOS 13.0, *)

lazy var datasource = UITableViewDiffableDataSource<String, String>()

}

Now it’s working!

So can we use DiffableDataSource while supporting iOS 12?

We sure can. But you need to do two things to make it right.

First, we need to understand the iOS 12 still uses the cellForRow() method of UITableViewDatasource protocol.

When you implement DiffableDataSource, cellForNow() is not the method that modifies the tableview cells, and you are now doing it when you initialize your diffableDataSource with the cellProvider argument.

This means you need to unite the code to a third function so you won’t have code duplication in your project.

Second, (here it comes…), you need to create a fallback whenever you need to refresh your table view.

Something like that:

if #available(iOS 13.0, *) {

updateSnapshotFromNewData(newData: newData)

} else {

tableView.reloadData()

}

Summary

DiffableDataSource is a great feature. Most of your users are probably already run iOS 13, and with an easy implementation, you can give them better user experience and still keep support for those iOS 12 users. God knows what they are waiting for with the update.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s