2
votes

I'm using NSFetchedResultsController with UICollectionView. Whenever I get a call from the server I update the Core data table and from using core data notification I update the UICollectionView. When I do this, I'm getting an error like this,

CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (12) must be equal to the number of items contained in that section before the update (11), plus or minus the number of items inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

From this thread Assertion failure when i use the Add Function

I understand that my Collectionview is being updated when it is undergoing updation. My question is, How can I prevent this scenario?

my code:

  • (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { @synchronized(self) { if (controller == myFetchedResultsController) { if ([self.sectionChangesInCollectionView count] > 0) { [self.myCollectionView performBatchUpdates:^{

                for (NSDictionary *change in self.sectionChangesInCollectionView)
                {
                    [change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop)
    

    {

                        NSFetchedResultsChangeType type = [key unsignedIntegerValue];
                        switch (type)
                        {
                            case NSFetchedResultsChangeInsert:
                                [self.myCollectionView insertSections:[NSIndexSet indexSetWithIndex:[obj
    

    unsignedIntegerValue]]]; break; case NSFetchedResultsChangeDelete: [self.myCollectionView deleteSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]]]; break; case NSFetchedResultsChangeUpdate: [self.myCollectionView reloadSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]]]; break; } }]; } } completion:nil]; }

        if ([self.objectChangesInCollectioView count] > 0 && [self.sectionChangesInCollectionView count] == 0)
        {
    
            if ([self shouldReloadCollectionViewToPreventKnownIssue] ||
    

    self.myCollectionView.window == nil) { // This is to prevent a bug in UICollectionView from occurring. // The bug presents itself when inserting the first object or deleting the last object in a collection view. // UICollectionView Assertion failure // This code should be removed once the bug has been fixed, it is tracked in OpenRadar // http://openradar.appspot.com/12954582 [self.myCollectionView reloadData];

            }
            else
            {
    
    
                [self.myCollectionView performBatchUpdates:^{
    
                    for (NSDictionary *change in self.objectChangesInCollectioView)
                    {
                        [change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop)
    

    {

                            NSFetchedResultsChangeType type = [key unsignedIntegerValue];
                            switch (type)
                            {
                                case NSFetchedResultsChangeInsert:
                                {
                                    dispatch_async(dispatch_get_main_queue(), ^
                                                   {
                                                       [self.myCollectionView insertItemsAtIndexPaths:@[obj]];
                                                   });
                                    break;
                                }
                                case NSFetchedResultsChangeDelete:
                                {
                                    dispatch_async(dispatch_get_main_queue(), ^
                                                   {
                                                       [self.myCollectionView deleteItemsAtIndexPaths:@[obj]];
                                                   });
                                    break;
                                }
                                case NSFetchedResultsChangeUpdate:
                                {
                                    dispatch_async(dispatch_get_main_queue(), ^
                                                   {
                                                       [self.myCollectionView reloadItemsAtIndexPaths:@[obj]];
                                                   });
                                    break;
                                }
                                case NSFetchedResultsChangeMove:
                                {
                                    dispatch_async(dispatch_get_main_queue(), ^
                                                   {
                                                       [self.myCollectionView moveItemAtIndexPath:obj[0]
    

    toIndexPath:obj1]; }); break; } } }]; } } completion:nil]; } }

        [self.sectionChangesInCollectionView removeAllObjects];
        [self.objectChangesInCollectioView removeAllObjects];
    }
    else
    {
    
    }
    

    } }

pragma mark - collectionView bug fix method

  • (BOOL)shouldReloadCollectionViewToPreventKnownIssue { __block BOOL shouldReload = NO;

    for (NSDictionary *change in self.objectChangesInCollectioView) { [change enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { NSFetchedResultsChangeType type = [key unsignedIntegerValue]; NSIndexPath *indexPath = obj; switch (type) { case NSFetchedResultsChangeInsert: if ([self.myCollectionView numberOfItemsInSection:indexPath.section] == 0) { shouldReload = YES; } else { shouldReload = NO; } break; case NSFetchedResultsChangeDelete: if ([self.myCollectionView numberOfItemsInSection:indexPath.section] == 1) { shouldReload = YES; } else { shouldReload = NO; } break; case NSFetchedResultsChangeUpdate: shouldReload = NO; break; case NSFetchedResultsChangeMove: shouldReload = NO; break; } }]; }

    return shouldReload; }

1

1 Answers

0
votes

Delete the core data item and let the delegate callbacks take care of deleting the table view row. Check out this answer.