Swiftpack.co -  FelixHerrmann/FHDiffableViewControllers as Swift Package
Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
UITableViewController and UICollectionViewController based on a DiffableDataSource.
.package(url: "https://github.com/FelixHerrmann/FHDiffableViewControllers.git", from: "2.1.3")


GitHub version GitHub license Twitter

UITableViewController and UICollectionViewController based on a DiffableDataSource.


  • macOS 10.15+ (Catalyst)
  • iOS 13.0+
  • tvOS 13.0+


Swift Package Manager

Add the following to the dependencies of your Package.swift:

.package(url: "https://github.com/FelixHerrmann/FHDiffableViewControllers.git", from: "x.x.x")


Download the files in the Sources folder and drag them into you project.


If you are using Swift Package Manager, you have to import FHDiffableViewControllers to your file with import FHDiffableViewControllers. You can also import it globally with @_exported import FHDiffableViewControllers. (e.g. in AppDelegate.swift)

Now you can inherit your view controller class from FHDiffableTableViewController and FHDiffableCollectionViewController.

But first we need a SectionIdentifier and ItemIdentifier which will be used for the generic types. Both types have to conform to Hashable.

enum Section {
    case main, detail

struct Item: Hashable {
    var title: String

It is recommend to conform the item to Identifiable because the app crashes if there are duplicates in the data source!

These types can be used like that:

class ViewController: FHDiffableTableViewController<Section, Item> {
    override func viewDidLoad() {
                sectionIdentifier: .main,
                itemIdentifiers: [
                    Item(title: "First Item"),
                    Item(title: "Second Item")
                sectionIdentifier: .detail,
                itemIdentifiers: [
                    Item(title: "Third Item")
        ], animatingDifferences: false)

This is the most simple implementation of a FHDiffableTableViewController.

The cell selection can be implemented like that:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let item = dataSource.itemIdentifier(for: indexPath)
    /*do your actions with the selected item*/

Customize Cells

In order to use custom cells, the cellProvider property must be overwritten. This works exactly the same for table view and collection view.

override var cellProvider: UITableViewDiffableDataSource<Section, Item>.CellProvider {
    return { (tableView, indexPath, item) in
        let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as? CustomCell
        cell?.textLabel?.text = item.title
        return cell

Do not forget to register the cell before you call applySnapshot(_:) the first time!

tableView.register(CustomCell.self, forCellReuseIdentifier: "customCell")

Customize Header and Footer Views (only collection view)

In order to use custom header or footer views, the supplementaryViewProvider property must be overwritten.

override var supplementaryViewProvider: UICollectionViewDiffableDataSource<Section, Item>.SupplementaryViewProvider? {
    return { (collectionView, kind, indexPath) in
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "customHeader", for: indexPath) as? CustomHeader
        switch self.dataSource.snapshot().sectionIdentifiers[indexPath.section] {
        case .main:
            headerView?.backgroundColor = .systemGreen
        case .detail:
            headerView?.backgroundColor = .systemPink
        return headerView

Do not forget to register the cell before you call applySnapshot(_:) the first time!

collectionView.register(CustomHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "customHeader")

Custom Data Source

In case you want to change the behavior of the title creation or you want to use section index titles and other features you have to subclass the appropriate data source. For the table view it could look something like that:

class CustomDataSource: UITableViewDiffableDataSource<Section, Item> {
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch snapshot().sectionIdentifiers[section] {
        case .main:
            return "Main"
        case .detail:
            return "Detail"

Use UICollectionViewDiffableDataSource for collection view.

So that it can be used in our view controller we have to create a lazy var of this and override the dataSource property with it.

lazy var customDataSource = CustomDataSource(tableView: tableView, cellProvider: cellProvider)

override var dataSource: UITableViewDiffableDataSource<Section, Item> {
    return customDataSource

Custom applySnapshot(_:)

You are not forced to use applySnapshot(_:) in combination with FHDiffableDataSourceSection array to apply snapshots to your dataSource. You can override the applySnapshot(_:) to change its behavior, create your own applySnapshot() method or do it manually as follows:

var snapshot = FHSnapshot()
snapshot.appendSections([.main, .detail])
snapshot.appendItems([Item(title: "Main Item")], toSection: .main)
snapshot.appendItems([Item(title: "Detail Item")], toSection: .detail)
dataSource.apply(snapshot, animatingDifferences: true, completion: nil)


The FHDiffableCollectionViewController has a custom initializer, which is based on an enum. This contains a case for UICollectionViewFlowLayout, for UICollectionViewCompositionalLayout, for a custom UICollectionViewLayout or a default case.

The default case creates a compositional layout, which is only intended to be used for testing.


FHConstraints is available under the MIT license. See the LICENSE file for more info.


Stars: 1
Last commit: 5 weeks ago

Ad: Job Offers

iOS Software Engineer @ Perry Street Software
Perry Street Software is Jack’d and SCRUFF. We are two of the world’s largest gay, bi, trans and queer social dating apps on iOS and Android. Our brands reach more than 20 million members worldwide so members can connect, meet and express themselves on a platform that prioritizes privacy and security. We invest heavily into SwiftUI and using Swift Packages to modularize the codebase.

Release Notes

5 weeks ago

• FHSnapshotData replaced with FHSection • documentations improved (DocC support included)

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API