NSFetchedResultsContollerDelegate for CollectionView

前端 未结 6 1083
悲哀的现实
悲哀的现实 2020-11-30 21:10

I\'d like to use the NSFetchedResultsControllerRelegate in a CollectionViewController. Therefore I just changed the method for the TableViewController for the CollectionView

6条回答
  •  时光说笑
    2020-11-30 21:41

    A version for 2020:

    Based on the incredible answers above,

    Which matches the familiar Apple example for tables:

    Consider the familiar Apple example for table views:

    https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/nsfetchedresultscontroller.html#//apple_ref/doc/uid/TP40001075-CH8-SW1

    at the heading

    "Communicating Data Changes to the Table View" ...

    So,

    func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
        case .insert:
            insertRows(at: [newIndexPath!], with: .fade)
        case .delete:
            deleteRows(at: [indexPath!], with: .fade)
        case .update:
            reloadRows(at: [indexPath!], with: .fade)
        case .move:
            moveRow(at: indexPath!, to: newIndexPath!)
        }
    }
    

    .

    Here's the "similar pattern" to copy and paste for collection views, with current syntax etc.

    var ops: [BlockOperation] = []
    
    func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
            case .insert:
                ops.append(BlockOperation(block: { [weak self] in
                    self?.insertItems(at: [newIndexPath!])
                }))
            case .delete:
                ops.append(BlockOperation(block: { [weak self] in
                    self?.deleteItems(at: [indexPath!])
                }))
            case .update:
                ops.append(BlockOperation(block: { [weak self] in
                    self?.reloadItems(at: [indexPath!])
                }))
            case .move:
                ops.append(BlockOperation(block: { [weak self] in
                    self?.moveItem(at: indexPath!, to: newIndexPath!)
                }))
            @unknown default:
                break
        }
    }
    
    func controllerDidChangeContent(_ controller: NSFetchedResultsController) {
        performBatchUpdates({ () -> Void in
            for op: BlockOperation in self.ops { op.start() }
        }, completion: { (finished) -> Void in self.ops.removeAll() })
    }
    
    deinit {
        for o in ops { o.cancel() }
        ops.removeAll()
    }
    

    .

    (I have just left out the "sections" material, which is the same.)

    Do nothing in controllerWillChangeContent?

    In the magnificent answer by @PhuahYeeKeat , in controllerWillChangeContent the ops array is cleaned out. I may be wrong but there's no reason to do that; it is reliably emptied by the batch updates cycle. Simply do nothing in controllerWillChangeContent.

    Is there a race?

    I have a concern about what happens if a new didChange arrives while the performBatchUpdates is processing the previous batch.

    I really don't know if performBatchUpdates makes a local copy or what - in which case, the global one should be deleted before doing performBatchUpdates ?

    IDK.

提交回复
热议问题