I\'d like to use the NSFetchedResultsControllerRelegate in a CollectionViewController. Therefore I just changed the method for the TableViewController for the CollectionView
Based on the incredible answers above,
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.)
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.
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.