Search code examples
iosswiftuitableviewuikit

How to move UITableView cells while using UITableViewDiffableDataSource?


I am trying to make my tableView cells movable, but it needs 2 or 3 functions from UITableViewDataSource protocol, If I tried to implement the delegate in my viewController It will ask for numberOfRowsInSection and cellForRowAtIndexPath functions which are already covered by the new UITableViewDiffableDataSource.

How can I achieve this behavior while using the new UITableViewDiffableDataSource?


Solution

  • To flesh out Tung Fam's answer, here is a complete implementation:

    class MovableTableViewDataSource: UITableViewDiffableDataSource<Int, Int> {
    
        override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
            super.tableView(tableView, moveRowAt: sourceIndexPath, to: destinationIndexPath)
    
            var snapshot = self.snapshot()
            if let sourceId = itemIdentifier(for: sourceIndexPath) {
                if let destinationId = itemIdentifier(for: destinationIndexPath) {
                    guard sourceId != destinationId else {
                        return // destination is same as source, no move.
                    }
                    // valid source and destination
                    if sourceIndexPath.row > destinationIndexPath.row {
                        snapshot.moveItem(sourceId, beforeItem: destinationId)
                    } else {
                        snapshot.moveItem(sourceId, afterItem: destinationId)
                    }
                } else {
                    // no valid destination, eg. moving to the last row of a section
                    snapshot.deleteItems([sourceId])
                    snapshot.appendItems([sourceId], toSection: snapshot.sectionIdentifiers[destinationIndexPath.section])
                }
            }
    
            apply(snapshot, animatingDifferences: false, completion: nil)
        }
    }
    

    It will crash if animatingDifferences is set true (animating is not really desirable here anyway).

    I'm not sure whether calling super.tableView(move…) is necessary, but it doesn't seem to do any harm.