soffes / sstoolkit

A collection of well-documented iOS classes for making life easier
MIT License
3.31k stars 573 forks source link

SSCollectionView doesn't function correctly when populated via NSFetchedResultsController #105

Closed P120D1GY closed 12 years ago

P120D1GY commented 12 years ago

Hello,

When trying to populate a SSCollectionView via NSFetchedResultsControllerDelegate methods, grid items don't appear during initial insertItemsAtIndexPaths between beginUpdates/endUpdates. Items are being created in NSFetchedResultsChangeInsert case, but nothing shows up. If I close the app then re-launch, grid items appear.

The following code is in a sub-class of SSCollectionViewController:

//=========================================================
// NSFetchedResultsControllerDelegate
//=========================================================
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.collectionView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    switch(type) {

        case NSFetchedResultsChangeInsert: {
            [self.collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withItemAnimation:SSCollectionViewItemAnimationFade];

            break;
        }

        case NSFetchedResultsChangeDelete: {
            [self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath] withItemAnimation:SSCollectionViewItemAnimationFade];

            break;
        }

        case NSFetchedResultsChangeUpdate: {
            [self configureItem:[self.collectionView itemForIndexPath:indexPath] atIndexPath:indexPath];

            break;
        }

        case NSFetchedResultsChangeMove:
            [self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath] withItemAnimation:SSCollectionViewItemAnimationFade];

            [self.collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withItemAnimation:SSCollectionViewItemAnimationFade];

            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [self.collectionView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withItemAnimation:SSCollectionViewItemAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withItemAnimation:SSCollectionViewItemAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.collectionView endUpdates];
}
soffes commented 12 years ago

Interesting. I'm sorry you're having trouble with it. I am using this functionality in a few of my apps and it's working fine. I wonder if it's something Core Data related specific to your situation. Here's the code I use in my delegate:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.collectionView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch(type) {
        case NSFetchedResultsChangeInsert: {
            [self.collectionView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                              withItemAnimation:SSCollectionViewItemAnimationFade];
            break;
    }

    case NSFetchedResultsChangeDelete: {
        [self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                          withItemAnimation:SSCollectionViewItemAnimationFade];
        break;
        }
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath {

    SSCollectionView *collectionView = self.collectionView;

    switch(type) {
        case NSFetchedResultsChangeInsert: {
            [collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                                  withItemAnimation:SSCollectionViewItemAnimationFade];
            break;
        }

        case NSFetchedResultsChangeDelete: {
            [collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                                  withItemAnimation:SSCollectionViewItemAnimationFade];
            break;
        }

        case NSFetchedResultsChangeUpdate: {
            [self _configureItem:[collectionView itemForIndexPath:indexPath] atIndexPath:indexPath];
            break;
        }

        case NSFetchedResultsChangeMove: {
            [collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                                  withItemAnimation:SSCollectionViewItemAnimationFade];
            [collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                                  withItemAnimation:SSCollectionViewItemAnimationFade];
            break;
        }
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.collectionView endUpdates];
}
P120D1GY commented 12 years ago

Looks like it was an issue with our Core Data implementation. Thanks!