Created
October 10, 2017 23:15
-
-
Save Sorix/987af88f82c95ff8c30b51b6a5620657 to your computer and use it in GitHub Desktop.
NSFetchedResultsControllerDelegate for UICollectionView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protocol FRCCollectionViewDelegate: class { | |
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell | |
} | |
class FRCCollectionViewDataSource<FetchRequestResult: NSFetchRequestResult>: NSObject, UICollectionViewDataSource, NSFetchedResultsControllerDelegate { | |
let frc: NSFetchedResultsController<FetchRequestResult> | |
weak var collectionView: UICollectionView? | |
weak var delegate: FRCCollectionViewDelegate? | |
private var blockOperation = BlockOperation() | |
init(fetchRequest: NSFetchRequest<FetchRequestResult>, context: NSManagedObjectContext, sectionNameKeyPath: String?) { | |
frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: sectionNameKeyPath, cacheName: nil) | |
super.init() | |
frc.delegate = self | |
} | |
func performFetch() throws { | |
try frc.performFetch() | |
} | |
func object(at indexPath: IndexPath) -> FetchRequestResult { | |
return frc.object(at: indexPath) | |
} | |
// MARK: - UICollectionViewDataSource | |
func numberOfSections(in collectionView: UICollectionView) -> Int { | |
return frc.sections?.count ?? 0 | |
} | |
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { | |
guard let sections = frc.sections else { return 0 } | |
return sections[section].numberOfObjects | |
} | |
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { | |
if let delegate = delegate { | |
return delegate.collectionView(collectionView, cellForItemAt: indexPath) | |
} else { | |
return UICollectionViewCell() | |
} | |
} | |
// MARK: - NSFetchedResultsControllerDelegate | |
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { | |
blockOperation = BlockOperation() | |
} | |
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { | |
let sectionIndexSet = IndexSet(integer: sectionIndex) | |
switch type { | |
case .insert: | |
blockOperation.addExecutionBlock { | |
self.collectionView?.insertSections(sectionIndexSet) | |
} | |
case .delete: | |
blockOperation.addExecutionBlock { | |
self.collectionView?.deleteSections(sectionIndexSet) | |
} | |
case .update: | |
blockOperation.addExecutionBlock { | |
self.collectionView?.reloadSections(sectionIndexSet) | |
} | |
case .move: | |
assertionFailure() | |
break | |
} | |
} | |
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { | |
switch type { | |
case .insert: | |
guard let newIndexPath = newIndexPath else { break } | |
blockOperation.addExecutionBlock { | |
self.collectionView?.insertItems(at: [newIndexPath]) | |
} | |
case .delete: | |
guard let indexPath = indexPath else { break } | |
blockOperation.addExecutionBlock { | |
self.collectionView?.deleteItems(at: [indexPath]) | |
} | |
case .update: | |
guard let indexPath = indexPath else { break } | |
blockOperation.addExecutionBlock { | |
self.collectionView?.reloadItems(at: [indexPath]) | |
} | |
case .move: | |
guard let indexPath = indexPath, let newIndexPath = newIndexPath else { return } | |
blockOperation.addExecutionBlock { | |
self.collectionView?.moveItem(at: indexPath, to: newIndexPath) | |
} | |
} | |
} | |
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { | |
collectionView?.performBatchUpdates({ | |
self.blockOperation.start() | |
}, completion: nil) | |
} | |
} |
@tengelmeier any solution for this ?
My UI freezes during significant, multi-object sync operations via iCloud; is it possible the cause is what @tengelmeier commented?
Update: It seems that the approach used in this 2020 Stack Overflow answer is not causing the UI to be frozen.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The current version does not work on iOS 12 as the NSBlockOperation blocks are executed parallel on background threads but need to be performed on the main thread.