Skip to content

Instantly share code, notes, and snippets.

@tomasharkema
Last active August 20, 2020 09:25
Show Gist options
  • Save tomasharkema/b633709c1fd8edb5b462f76bde4f807c to your computer and use it in GitHub Desktop.
Save tomasharkema/b633709c1fd8edb5b462f76bde4f807c to your computer and use it in GitHub Desktop.
UICollectionViewDiffableDataSource iOS 12
//
// DataSource.swift
//
// Created by Tomas Harkema on 06/06/2019.
// Copyright © 2019 Tomas Harkema. All rights reserved.
//
import UIKit
import DeepDiff // https://github.com/onmyway133/DeepDiff
enum Section: Hashable {
case empty
}
class DataSource<Item: Hashable & DiffAware>: NSObject {
static func create(collectionView: UICollectionView, cellProvider: @escaping (UICollectionView, IndexPath, Item) -> UICollectionViewCell?) -> DataSource<Item> {
if #available(iOS 13, *) {
return NewDataSource(collectionView: collectionView, cellProvider: cellProvider)
} else {
return OldDataSource(collectionView: collectionView, cellProvider: cellProvider)
}
}
func apply(newValue: [Item]) {
fatalError()
}
func itemIdentifier(for indexPath: IndexPath) -> Item? {
fatalError()
}
}
@available(iOS 13, *)
class NewDataSource<Item: Hashable & DiffAware>: DataSource<Item> {
private let dataSource: UICollectionViewDiffableDataSource<Section, Item>
init(collectionView: UICollectionView, cellProvider: @escaping (UICollectionView, IndexPath, Item) -> UICollectionViewCell?) {
dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: cellProvider)
super.init()
}
override func apply(newValue: [Item]) {
let snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.empty])
snapshot.appendItems(newValue)
dataSource.apply(snapshot)
}
override func itemIdentifier(for indexPath: IndexPath) -> Item? {
return dataSource.itemIdentifier(for: indexPath)
}
}
@available(iOS, deprecated: 12.4, obsoleted: 12.4)
class OldDataSource<Item: Hashable & DiffAware>: DataSource<Item>, UICollectionViewDataSource {
private let collectionView: UICollectionView
private var backingStore = [Item]()
private let cellProvider: (UICollectionView, IndexPath, Item) -> UICollectionViewCell?
init(collectionView: UICollectionView, cellProvider: @escaping (UICollectionView, IndexPath, Item) -> UICollectionViewCell?) {
self.collectionView = collectionView
self.cellProvider = cellProvider
super.init()
collectionView.dataSource = self
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return backingStore.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return cellProvider(collectionView, indexPath, backingStore[indexPath.row])!
}
override func apply(newValue: [Item]) {
DispatchQueue.main.async {
let changes = diff(old: self.backingStore, new: newValue)
self.collectionView.reload(changes: changes, updateData: {
self.backingStore = newValue
})
}
}
override func itemIdentifier(for indexPath: IndexPath) -> Item? {
return backingStore[indexPath.item]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment