Skip to content

Instantly share code, notes, and snippets.

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 danielgalasko/fe37876f7b3227d5c24e to your computer and use it in GitHub Desktop.
Save danielgalasko/fe37876f7b3227d5c24e to your computer and use it in GitHub Desktop.
A UICollectionView + NSFetchedResultsControllerDelegate companion designed to assist with managing inserts, updates, moves and deletions into a UICollectionView. Simply instantiate the companion with a fetchedResultsController, supply it with a delegate, and once the delegate calls the `collectionViewFetchedResultsControllerDelegateCompanionDidF…
/// Manages all the updates, inserts and deletes nicely so that you can worry about only the animation
/// @note Doesnt work with section changes as of yet
class CollectionViewFetchedResultsControllerDelegateCompanion: NSObject,NSFetchedResultsControllerDelegate {
var delegate: CollectionViewFetchedResultsControllerDelegateCompanionDelegate
private var changesKeyedByType:[NSFetchedResultsChangeType:[NSIndexPath]] = [:]
init(fetchedResultsController: NSFetchedResultsController,delegate: CollectionViewFetchedResultsControllerDelegateCompanionDelegate) {
self.delegate = delegate
super.init()
fetchedResultsController.delegate = self
}
func performUpdatesToCollectionView(collectionView: UICollectionView, completionHandler: ((completed: Bool) -> Void )?) {
if changesKeyedByType.count == 0 {
completionHandler?(completed: false)
return
}
collectionView.performBatchUpdates({ () -> Void in
//inserts
if let inserts = self.changesKeyedByType[.Insert] {
//for indexPath in inserts {println("inserting at\(indexPath)")}
collectionView.insertItemsAtIndexPaths(inserts)
}
//deletes
if let deletes = self.changesKeyedByType[.Delete] {
//for indexPath in deletes {println("deleting at\(indexPath)")}
collectionView.deleteItemsAtIndexPaths(deletes)
}
//updates
if let updates = self.changesKeyedByType[.Update] {
//for indexPath in updates {println("updating at\(indexPath)")}
collectionView.reloadItemsAtIndexPaths(updates)
}
//moves
if let moves = self.changesKeyedByType[.Move] {
for var index = 0; index < moves.count; index = index + 2 {
//println("Moving from \(moves[index]) to \(moves[index + 1] )")
collectionView.moveItemAtIndexPath(moves[index], toIndexPath: moves[index + 1])
}
}
}, completion: { (complete) -> Void in
self.changesKeyedByType.removeAll(keepCapacity: false)
completionHandler?(completed: complete)
})
}
/// MARK: - NSFetchedResultsControllerDelegate -
func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.delegate.collectionViewFetchedResultsControllerDelegateCompanionWillBeginUpdatingContent?(self)
self.changesKeyedByType.removeAll(keepCapacity: false)
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
self.delegate.collectionViewFetchedResultsControllerDelegateCompanionDidFinishUpdatingContent(self, hasUpdates: self.changesKeyedByType.count > 0)
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
var changesArrayForType: [NSIndexPath] = {
if let changes = self.changesKeyedByType[type] {
return changes
} else {
self.changesKeyedByType[type] = []
return self.changesKeyedByType[type]!
}
}()
if contains(changesArrayForType, indexPath ?? newIndexPath!) {
//println("See you tried to add a duplicate")
return
}
switch type {
case .Insert:
changesArrayForType.append(newIndexPath!)
case .Delete:
changesArrayForType.append(indexPath!)
case .Move:
changesArrayForType.append(indexPath!)
changesArrayForType.append(newIndexPath!)
case .Update:
changesArrayForType.append(indexPath!)
}
changesKeyedByType.updateValue(changesArrayForType, forKey: type)
}
}
@danielgalasko
Copy link
Author

Example usage - when the delegate calls back with didFinishUpdatingContent

- (void)collectionViewFetchedResultsControllerDelegateCompanionDidFinishUpdatingContent:(CollectionViewFetchedResultsControllerDelegateCompanion *)companion hasUpdates:(BOOL)hasUpdates {
    if (hasUpdates) {
        [self.collectionViewDataSource reloadData];
        [companion performUpdatesToCollectionView:self.collectionView completionHandler:nil];
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment