Much of the suffering above relates to a bug known to Apple, and reportedly fixed.
https://developer.apple.com/forums/thread/692357
In the words of 'Frameworks Engineer' in Apple Forums at link above:
> Before iOS 15, there was a bug in the implementation of how
> NSDiffableDataSourceSnapshot was bridged between Swift and
> Objective-C, which caused the internally-stored reloaded identifiers
> to be lost during the bridging process (which is what happens when you
> bridge from NSDiffableDataSourceSnapshotReference to
> NSDiffableDataSourceSnapshot using the as keyword). . . as of iOS 15, they
> now work as intended in Swift as well.
Now, in theory, one no longer has to create a snapshot from scratch. One can use Apple's specified syntax of
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
let snapshot = snapshot as NSDiffableDataSourceSnapshot<String, NSManagedObjectID>
self.apply(newSnapshot, animatingDifferences: true)
}
I have now implemented this and once the snapshot is cast, it *seems* to work. YMMV.
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
}
}()