Search code examples
ioscore-dataios13

How to get a diffable snapshot from an NSFetchResultsController in iOS 13?


So here we are in WWDC 2019 video 230, and starting at about minute 14 it is claimed that NSFetchedResultsController now vends an NSDiffableDataSourceSnapshot, so we can just apply it directly to a diffable data source (UITableViewDiffableDataSource).

But this is not quite what they say, or what we get. What we get, in the delegate method controller(_:didChangeContentWith:), is an NSDiffableDataSourceReference. How do we get from this to an actual snapshot, and what should my diffable data source generic types be?


Solution

  • The diffable data source should be declared with generic types String and NSManagedObjectID. Now you can cast the reference to a snapshot:

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
        let snapshot = snapshot as NSDiffableDataSourceSnapshot<String,NSManagedObjectID>
        self.ds.apply(snapshot, animatingDifferences: false)
    }
    

    This leaves open the question of how you're going to populate the cell. In the diffable data source (self.ds in my example), when you populate the cell, return to the fetched results controller and fetch the actual data object.

    For example, in my table view I am displaying the name of a Group in each cell:

    lazy var ds : UITableViewDiffableDataSource<String,NSManagedObjectID> = {
        UITableViewDiffableDataSource(tableView: self.tableView) {
            tv,ip,id in
            let cell = tv.dequeueReusableCell(withIdentifier: self.cellID, for: ip)
            cell.accessoryType = .disclosureIndicator
            let group = self.frc.object(at: ip)
            cell.textLabel!.text = group.name
            return cell
        }
    }()