- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { shouldReloadCollectionView = NO; blockOperation = [NSBlockOperation new]; } - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { __weak UICollectionView *collectionView = self.collectionView; switch (type) { case NSFetchedResultsChangeInsert: { [blockOperation addExecutionBlock:^{ [collectionView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]]; }]; break; } case NSFetchedResultsChangeDelete: { [blockOperation addExecutionBlock:^{ [collectionView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]]; }]; break; } case NSFetchedResultsChangeUpdate: { [blockOperation addExecutionBlock:^{ [collectionView reloadSections:[NSIndexSet indexSetWithIndex:sectionIndex]]; }]; break; } default: break; } } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { __weak UICollectionView *collectionView = self.collectionView; switch (type) { case NSFetchedResultsChangeInsert: { if ([self.collectionView numberOfSections] > 0) { if ([self.collectionView numberOfItemsInSection:indexPath.section] == 0) { shouldReloadCollectionView = YES; } else { [blockOperation addExecutionBlock:^{ [collectionView insertItemsAtIndexPaths:@[newIndexPath]]; }]; } } else { shouldReloadCollectionView = YES; } break; } case NSFetchedResultsChangeDelete: { if ([self.collectionView numberOfItemsInSection:indexPath.section] == 1) { shouldReloadCollectionView = YES; } else { [blockOperation addExecutionBlock:^{ [collectionView deleteItemsAtIndexPaths:@[indexPath]]; }]; } break; } case NSFetchedResultsChangeUpdate: { [blockOperation addExecutionBlock:^{ [collectionView reloadItemsAtIndexPaths:@[indexPath]]; }]; break; } case NSFetchedResultsChangeMove: { [blockOperation addExecutionBlock:^{ [collectionView moveItemAtIndexPath:indexPath toIndexPath:newIndexPath]; }]; break; } default: break; } } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { // Checks if we should reload the collection view to fix a bug @ http://openradar.appspot.com/12954582 if (shouldReloadCollectionView) { [self.collectionView reloadData]; } else { [self.collectionView performBatchUpdates:^{ [blockOperation start]; } completion:nil]; } }