How to use Core Data with Diffable Data Source - a minimal example
Tags: ios, swift
Published: 2020-09-28 19:44:03

If you have been developing iOS apps for some time, setting up Table Views and Collection Views is likely muscle memory. You prepare the UI component, set datasource and delegate and then implement methods that tell said component how many sections and rows in each section to accept. The last needed step is to configure cell for each row.

Using this old setup with Core Data means in most cases `NSFetchedResultsController` and implementation of its delegate which tells you when data content changed and you need to update the Table/Collection View accordingly.

Diffable Data Sources make this much easier. But also the process is totally different and can be a bit hard to get used to.

I am writing this short example for myself and other to speed up setting up Diffable in new projects with Core Data. The result is three shorter methods that make the initial collection view work.

I am using `UICollectionView` in this example, but `UITableView` is basically identical.

Note: In your project substitute `Model` class from my example with your own Core Data entity.

Let's start with declaring properties:
```swift
var datasource: UICollectionViewDiffableDataSource<Int, Model>!
var fetchedResultsController: NSFetchedResultsController<Model>!
```

Note: For `UITableView` you would use `UITableViewDiffableDataSource`. The `Int` is used because this requires type for section. If you have just one you can use `Int`, `String` and then pass either "0" or empty string.

### Configuring UICollectionViewDiffableDataSource

Next we configure the `datasource` like so:

```swift
func configureDatasource() {
        datasource = UICollectionViewDiffableDataSource(collectionView: collectionView, cellProvider: { (collectionView, indexPath, scan) -> UICollectionViewCell? in
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ModelCell", for: indexPath) as! ModelCell
            cell.configure(with: model)
            return cell
        })
}
```

All we need to do is to create an instance of `UICollectionViewDiffableDataSource`. We give it our `collectionView` and configure `cellProvider` which is modern version of the old `cellForRowAt` method.

This could be separate method we could pass in. Since this is an example and I have just a single I am using inline version. 

### NSFetchedResultsController

Time to configure the `NSFetchedResultsController`:

```swift
func initFetchedResultsController() {
        fetchedResultsController = NSFetchedResultsController(fetchRequest: Model.sortedFetchRequest, managedObjectContext: Database.shared.context, sectionNameKeyPath: nil, cacheName: nil)
        fetchedResultsController.delegate = self
        try! fetchedResultsController.performFetch()
}
```

### Animating changes

And almost as a last step we need to implement a method that will update our `collectionView` when data changes:

```swift
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
        var diffableDataSourceSnapshot = NSDiffableDataSourceSnapshot<Int, Model>()
        diffableDataSourceSnapshot.appendSections([0])
        diffableDataSourceSnapshot.appendItems(fetchedResultsController.fetchedObjects ?? [])
        datasource?.apply(diffableDataSourceSnapshot, animatingDifferences: view.window != nil)
}
```

And lastly we need to call these methods in `viewDidLoad`:

```swift
override func viewDidLoad() {
        super.viewDidLoad()
        configureDatasource()
        initFetchedResultsController()
}
```

Of course **this solution is not perfect** and is not meant to be. My goal was to show simplest working example to get started which you can tweak to your liking.

I write about iOS/Swift here and on my blog [nemecek.be](https://nemecek.be)