Diffable Data Source in iOS 13

Rameshwar Gade
Globant
Published in
4 min readJul 20, 2020

From the beginning of iOS SDK, Table views manage only the presentation of their data, they do not manage the data itself. To manage the data you provide the table with a data source object. that is an object that implements the UITableViewDataSource protocol. A data source object responds to data-related requests from the table. Also, provides the cells in TableView. we need to implement the protocol methods and make sure to sync our backing model with the data source properly to avoid any crashes.

optional func number of sections(in tableView: UITableView) -> Int
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

Also, If we need to perform updates for sections and rows in our TableView.

tableView.beginUpdates()// Delete section 1 and 2
tableView.reloadSections([1,2], with: .automatic)
// Insert at section 1 and row 1
tableView.insertRows(at: [IndexPath(row: 1, section: 1)], with: .automatic)
// delete at section 1 and row 3
tableView.deleteRows(at: [IndexPath(row: 3, section: 1)], with: .automatic)
tableView.endUpdates()

It’s pretty hard to make sure all the sections and rows are correctly updated for each insert, reload, and deletion based on the value between the old and new data.

This is the error that UIKit throws when we incorrectly update the TableView.

* Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Invalid update: invalid number of sections. The number of sections contained in the table view after the update (10) must be equal to the number of sections contained in the table view before the update (10), plus or minus the number of sections inserted or deleted (0 inserted, 1 deleted).’
***

In WWDC 2019 Apple announced a really cool feature for table views and collection views. UITableViewDiffableDataSource and UICollectionViewDiffableDataSource.

These new diffable data source classes allow us to define data sources for collection- and table views in terms of snapshots. Snapshot acts as a source of truth between our view and data source. The diffable data source will then compare the new snapshot to the old snapshot and it will automatically apply any insertions, deletions, and reordering of its contents. All the diffing, view update with animation will be performed automatically for us.

You can read more about this from Apple WWDC 2019 session

Here we will see Diffable Data Source for TableView. Since the table view data source is pretty much the same as the collection view version apart from some class names.

Diffable Data Source Diffing Strategy.

We need to provide sections and item type representation that can provide unique value. Both of them need to implement a Hashable protocol as per the declaration of the UITableViewDiffableDataSource class below.

@available(iOS 13.0, tvOS 13.0, *)
open class UITableViewDiffableDataSource<SectionIdentifierType, ItemIdentifierType> : NSObject, UITableViewDataSource where SectionIdentifierType : Hashable, ItemIdentifierType : Hashable

SectionIdentifierType and ItemIdentifierType are generic that we must provide when we declare and initialize the class. Diffable data source uses the hash values for all identifiers to determine what’s changed.

Now let’s look at another key player in using a diffable data source.

Snapshot:

Whenever a table view needs to updates, a data source snapshot must be created using the latest data and applied to the data source object. It has the same generic parameters as the diffable data source it’s applied to.

struct NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType> 
where SectionIdentifierType : Hashable, ItemIdentifierType : Hashable

Example:

We have to first create the SectionIdentifier and ItemIdentifier for UITableViewDiffableDataSource. We will use an enum to provide a section as they are already confirmed to Hashable protocol.

enum Section {
case City
}

And for the ItemIdentifier we will create a separate model.

struct MyCity: Hashable {
var cityName:String
}
Class ViewController: UIViewController {@IBOutlet weak var cityTextfield: UITextField!
@IBOutlet weak var tableview: UITableView!
private var cityList = [City(name: “Mumbai”), City(name: “Pune”), City(name: “Nasik”)]
fileprivate var dataSource: UITableViewDiffableDataSource!
override func viewDidLoad() {super.viewDidLoad()configureDataSource()createSnapshot()}

We don’t have to write the cellForRowAt indexPath and other methods instead we can just write a few lines of code to load UITableview.

func configureDataSource() {dataSource = UITableViewDiffableDataSource<Section, MyCity>(tableView: tableview) { (tableview, indexPath, city) -> UITableViewCell? in
let cell = tableview.dequeueReusableCell(withIdentifier: “cell”, for: indexPath)
cell.textLabel?.text = city.cityName
return cell
}

Now, We can edit our table view

func tableViewEditOperations() {let cityObject = City(cityName: cityTextfield.text ?? "")//Adding row to tableview
cityList.append(cityObject)
//Deleting row from Tableview
cityList.remove(at: 1)
//Inserting row to Tableview
cityList.insert(cityObject, at: 1)
createSnapshot()}

We have created a separate function for Snapshot. We just need to call this function after each operation so that it will differ the changes for you.

func createSnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Section, MyCity>()
snapshot.appendSections([.Main])
snapshot.appendItems(cityList,toSection:.Main)
dataSource.apply(snapshot, animatingDifferences:true)
}

The apply() method animates the changes if needed. We can see all the editing operations with the animation below.

Conclusion:-

The UITableViewDiffableDataSource simply manage data and provide cells for a table view. This is a generic class that removes a lot of boilerplate code enabling us to create a datasource object in a very declarative way.

--

--