Skip to content

Instantly share code, notes, and snippets.

@cwagdev
Last active June 21, 2018 19:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cwagdev/ffd390c95babe6f546a6d4f4c47d82fa to your computer and use it in GitHub Desktop.
Save cwagdev/ffd390c95babe6f546a6d4f4c47d82fa to your computer and use it in GitHub Desktop.
import UIKit
import CoreData
class BasicFetchedResultsControllerDelegate: NSObject, NSFetchedResultsControllerDelegate {
let tableView: UITableView
var controllerDidChangeContentCallback: (() -> Void)?
/// The threshold for the number of inserts, deletes, and reloads to peform using animations. If the threshold is exceeded, the table will be reloaded using `reloadData()`. The default value is `50`.
var numberOfRowOperationsThresholdBeforeFullReloadOccurs = 50
/// The animation used for all inserts, deletes, reloads, of both rows and sections.
var changeAnimation: UITableViewRowAnimation = .fade
private var rowInserts: [IndexPath] = []
private var rowDeletes: [IndexPath] = []
private var rowReloads: [IndexPath] = []
private var sectionInserts: [IndexSet] = []
private var sectionDeletes: [IndexSet] = []
init(tableView: UITableView, controllerDidChangeContentCallback: (() -> Void)? = nil) {
self.tableView = tableView
self.controllerDidChangeContentCallback = controllerDidChangeContentCallback
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
clearOperationArrays()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
sectionInserts.append(IndexSet(integer: sectionIndex))
case .delete:
sectionDeletes.append(IndexSet(integer: sectionIndex))
default: return
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
if let newIndexPath = newIndexPath {
rowInserts.append(newIndexPath)
}
case .delete:
if let indexPath = indexPath {
rowDeletes.append(indexPath)
}
case .update:
if let indexPath = indexPath {
rowReloads.append(indexPath)
}
case .move:
if let indexPath = indexPath, let newIndexPath = newIndexPath {
rowDeletes.append(indexPath)
rowInserts.append(newIndexPath)
}
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
let totalRowOperations = [rowInserts, rowDeletes, rowReloads].reduce(0) { (total, operations) in
return total + operations.count
}
if totalRowOperations > numberOfRowOperationsThresholdBeforeFullReloadOccurs {
tableView.reloadData()
} else {
tableView.beginUpdates()
sectionInserts.forEach { tableView.insertSections($0, with: changeAnimation) }
sectionDeletes.forEach { tableView.deleteSections($0, with: changeAnimation) }
tableView.insertRows(at: rowInserts, with: changeAnimation)
tableView.deleteRows(at: rowDeletes, with: changeAnimation)
tableView.reloadRows(at: rowReloads, with: changeAnimation)
tableView.endUpdates()
}
controllerDidChangeContentCallback?()
clearOperationArrays()
}
private func clearOperationArrays() {
rowInserts = []
rowDeletes = []
rowReloads = []
sectionInserts = []
sectionDeletes = []
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment