Hi,
I'm brand new to iPhone development (and first question posted here) and am sort of stuck with Core Data and Table Views.
In short, my app is crashing when I delete a row from my UITableView due to NSFetchedResultsChangeUpdate being called on a record that has already been removed due to a cascade delete on a self referring table.
Here is a description of the data model:
There are two Entities; Person and Connection.
Person contains name (String), connections (To Many Relationship to Connection->source, cascade delete rule) and connectedby (To Many Relationship to Connection->connection, cascade delete rule)
Connection contains relationship (String), source (Relationship to Person->connections, nullify delete rule) and connection (Relationship to Person->connectedby, nullify delete rule)
The idea being that there are two people connected by a relationship (eg Mother or Son)
In my TableViewController I implement the following:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
and
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
Person *person = nil;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
person = (Person *)[fetchedResultsController objectAtIndexPath:indexPath];
[self configureCell:(PersonTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
person = (Person *)[fetchedResultsController objectAtIndexPath:indexPath];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
and
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
Here are the sample records I created for testing this:
Person *person1 = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.managedObjectContext];
[person1 setName:[NSString stringWithFormat: @"Tommy"]];
Person *person2 = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.managedObjectContext];
[person2 setName:[NSString stringWithFormat: @"Jane"]];
Connection *connection = [NSEntityDescription insertNewObjectForEntityForName:@"Connection" inManagedObjectContext:managedObjectContext];
[connection setConnection:person2];
[connection setSource:person1];
[connection setRelationship:[NSString stringWithFormat:@"Mother"]];
Connection *connection2 = [NSEntityDescription insertNewObjectForEntityForName:@"Connection" inManagedObjectContext:managedObjectContext];
[connection2 setConnection:person1];
[connection2 setSource:person2];
[connection2 setRelationship:[NSString stringWithFormat:@"Son"]];
When I delete the record at indexPath[0,0] i.e. Jane in this example since the view is sorted by name, I generate the following error:
2010-10-19 16:09:01.461 HelpMe[6324:207]
Serious application error.
Exception was caught during Core Data change processing.
This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.
*** -[NSMutableArray objectAtIndex:]: index 1 beyond bounds [0 .. 0] with userInfo (null)
Detected an attempt to call a symbol in system libraries that is not present on the iPhone:
_Unwind_Resume called from function -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] in image CoreData.
The delete seems to correctly generate a NSFetchedResultsChangeDelete for indexPath [0,0] but also then immediately generates a NSFetchedResultsChangeUpdate for [0,1] which no longer exists since [0,1] is seemingly now in [0,0] after the delete.
Without the associated Connection record, it deletes fine.
I can seemingly work around this by simply calling [self.tableView reloadData] on controllerDidChangeContent instead of implementing begin/end updates and didChangeOnject: but I do not believe this is the proper way to handle this.
I appreciate any help anyone can offer.