Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save raypendergraph/f774e037f8e3b2fc170e73df966f50cb to your computer and use it in GitHub Desktop.
Save raypendergraph/f774e037f8e3b2fc170e73df966f50cb to your computer and use it in GitHub Desktop.
A generic reusable NSFetchedResultsControllerDelegate.
import UIKit
import CoreData
class GenericCollectionFetchResultsController: NSObject {
fileprivate var blockOperation = BlockOperation()
//This flag is a workaround to a bug in iOS: http://openradar.appspot.com/12954582
fileprivate var shouldReloadCollectionView = false
fileprivate var collectionView: UICollectionView!
init(collectionView: UICollectionView) {
self.collectionView = collectionView
}
deinit {
blockOperation.cancel()
}
}
extension GenericCollectionFetchResultsController: NSFetchedResultsControllerDelegate {
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
if collectionView.numberOfSections > 0 {
if collectionView.numberOfItems(inSection: newIndexPath!.section) == 0 {
shouldReloadCollectionView = true
} else {
blockOperation.addExecutionBlock {
self.collectionView.insertItems(at: [newIndexPath!])
}
}
} else {
shouldReloadCollectionView = true
}
case .update:
blockOperation.addExecutionBlock {
self.collectionView.reloadItems(at: [indexPath!])
}
case .move:
blockOperation.addExecutionBlock {
self.collectionView.moveItem(at: indexPath!, to: newIndexPath!)
}
case .delete:
if collectionView.numberOfItems(inSection: indexPath!.section) == 1 {
shouldReloadCollectionView = true
} else {
blockOperation.addExecutionBlock {
self.collectionView.deleteItems(at: [indexPath!])
}
}
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
blockOperation.addExecutionBlock {
self.collectionView.insertSections(IndexSet(integer: sectionIndex))
}
case .update:
blockOperation.addExecutionBlock {
self.collectionView.reloadSections(IndexSet(integer: sectionIndex))
}
case .delete:
blockOperation.addExecutionBlock {
self.collectionView.deleteSections(IndexSet(integer: sectionIndex))
}
default: break
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
shouldReloadCollectionView = false
blockOperation = BlockOperation()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
DispatchQueue.main.async {
if self.shouldReloadCollectionView {
self.collectionView.reloadData()
} else {
self.collectionView.performBatchUpdates({
self.blockOperation.start()
}, completion: nil)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment