views:

349

answers:

1

Hey guys, so I've got my NSFetchedResultsController working fine under the 3.1 SDK, however I start getting some weird errors, specifically in the delegate methods when I try it under 3.0. I've determined that this is related to the NSFetchedResultsControllerDelegate methods. This is what I have set up.

The inEditingMode stuff has to do with the way I've implemented adding another static section to the table.

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


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type{
    NSIndexSet *sectionSet = [NSIndexSet indexSetWithIndex:sectionIndex];

    if(self.inEditingMode){
        sectionSet = [NSIndexSet indexSetWithIndex:sectionIndex + 1];
    }

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:sectionSet withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:sectionSet withRowAnimation:UITableViewRowAnimationFade];
            break;
        default:
            [self.tableView reloadData];
            break;

    }
}


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

    if(self.inEditingMode){
        relativeIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section + 1];
        relativeNewIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:newIndexPath.section + 1];
    }

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:relativeNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:relativeIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        default:
            [self.tableView reloadData];
            break;
    }
}


-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller{
    [self.tableView endUpdates];
}

When I add an entity to the managed object context, I get the following error:

Serious application error.  Exception was caught during Core Data change processing: *** -[NSCFArray objectAtIndex:]: index (1) beyond bounds (1) with userInfo (null)

I put a breakpoint on objc_exception_throw, and the crash seems to be occuring inside of controllerDidChangeContent.

If I comment out all of the self.tableView methods, and put a single [self.tableView reloadData] inside of controllerDidChangeContent, everything works as expected.

Anybody have any idea as to why this is happening?

+2  A: 

In the documentation for NSFetchedResultsController, there is specific mention of a bug in the 3.0 implementation that results in a discrepancy between the number of sections reported by the controller and the number of sections expected by the UITableView. This is the workaround they provide:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    NSUInteger count = [[<#Fetched results controller#> sections] count];
    if (count == 0) {
        count = 1;
    }
    return count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    NSArray *sections = [<#Fetched results controller#> sections];
    NSUInteger count = 0;
    if ([sections count]) {
        id <NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:section];
        count = [sectionInfo numberOfObjects];
    }
    return count;
}

Note that this workaround is not required for OS 3.1, so this may explain why you are not seeing errors. The workaround is only necessary in 3.0 when sectionNameKeyPath is set to nil. If you are setting a value for sectionNameKeyPath, then this is likely not the issue.

glorifiedHacker
I forgot to add in my initial post, that I had already implemented this, but the problem was still persisting.
Scott Langendyk
Actually upon closer examination, and implementing this fix again, the problem dissapeared. I must have been doing something weird last time. Thanks alot!
Scott Langendyk
Glad to hear that it got fixed. Core Data and NSFetchedResultsController errors can be quite tricky to diagnose and fix.
glorifiedHacker