How can I reorder rows in UITableView that conforms to UITableViewDiffableDataSource?

114 Views Asked by At

To display list of items, I'm using UITableView which conforms to UITableViewDiffableDataSource. I want to reorder table rows. For that I've used tableView(_:canMoveRowAt:) and tableView(_:moveRowAt:to:). I couldn't see reorder button on the cells and both delegate functions are not triggered. But when I change the datasource to normal UITableViewDataSource , reordering is working.

import UIKit
import CoreData

typealias NewsItemDataSource = UITableViewDiffableDataSource<String, NSManagedObjectID>
typealias NewsItemSnapshot = NSDiffableDataSourceSnapshot<String, NSManagedObjectID>

class NewsItemViewController: UIViewController {
    
    
    private var tableView: UITableView!
    
    private var diffableDatasource: NewsItemDataSource!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureTableView()
        performFetch()
    }
    
    private func performFetch() {
        do {
            try fetchedResultsController.performFetch()
        } catch {
            
        }
    }
    
    private func configureTableView() {
        tableView = UITableView()
        tableView.register(with: NewsItemTableViewCell.self) // refactored with extension
        diffableDatasource = playsDiffableDataSource(tableView)
        tableView.dataSource = diffableDatasource
        tableView.isEditing = true
        tableView.allowsSelection = false
        tableView.delegate = self
    }
    
    func playsDiffableDataSource(_ tableView: UITableView) -> UITableViewDiffableDataSource<String, NSManagedObjectID> {
        let diffableDatasource = UITableViewDiffableDataSource<String, NSManagedObjectID>(tableView: tableView) { (tableView, indexPath, objectID) -> UITableViewCell? in
            guard let newsItem = try? CoreDataManager.shared.moc.existingObject(with: objectID) as? CDNewsItem else {
                return UITableViewCell()
            }
            let cell: NewsItemTableViewCell = tableView.dequeueReusableCell(for: indexPath)
            cell.configure(with: newsItem)
            return cell
        }
        return diffableDatasource
    }
    
    private lazy var fetchedResultsController: NSFetchedResultsController<CDNewsItem> = {
        // Create Fetch Request
        let fetchRequest = CDNewsItem.fetchRequest()
        
        // Configure Fetch Request
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "modificationDate", ascending: false)]
        fetchRequest.fetchBatchSize = 30
        
        // Create Fetched Results Controller
        let moc = CoreDataManager.shared.moc
        let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
                                                                  managedObjectContext: moc,
                                                                  sectionNameKeyPath: nil,
                                                                  cacheName: nil)
        
        // Configure Fetched Results Controller
        fetchedResultsController.delegate = self
        
        return fetchedResultsController
    }()
    
    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
      return true
    }
    
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        fetchedResultsController.fetchedObjects?.swapAt(sourceIndexPath.row, destinationIndexPath.row)
    }
    
    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
        return .none
    }

    func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
        return false
    }
    
}

extension PlaysListViewController: NSFetchedResultsControllerDelegate {
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
        guard let diffableDatasource else { return }
        diffableDatasource.apply(snapshot as NewsItemSnapshot, animatingDifferences: true)
    }
}

0

There are 0 best solutions below