Voici l'interface de ma classe contrôleur:NSFetchedResultsController: l'utilisation de NSManagedObjectContext lors de la mise à jour apporte crash
@interface ProjectListViewController : UITableViewController <NSFetchedResultsControllerDelegate> {
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
}
@end
J'utilise le code suivant à init fetchedResultsController:
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Create and configure a fetch request with the Project entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Project" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Create the sort descriptors array.
NSSortDescriptor *projectIdDescriptor = [[NSSortDescriptor alloc] initWithKey:@"projectId" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:projectIdDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Create and initialize the fetch results controller.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
self.fetchedResultsController = aFetchedResultsController;
fetchedResultsController.delegate = self;
Comme vous pouvez le voir , J'utilise le même managedObjectContext comme défini dans ma classe de contrôleur
Voici l'adoption du protocole NSFetchedResultsControllerDelegate:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self _configureCell:(TDBadgedCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
if (newIndexPath != nil) {
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else {
[tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
A l'intérieur du _configureCell: atIndexPath: méthode que j'ai le code suivant:
NSFetchRequest *issuesNumberRequest = [NSFetchRequest new];
NSEntityDescription *issueEntity = [NSEntityDescription entityForName:@"Issue" inManagedObjectContext:managedObjectContext];
[issuesNumberRequest setEntity:issueEntity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"projectId == %@", project.projectId];
[issuesNumberRequest setPredicate:predicate];
NSUInteger issuesNumber = [managedObjectContext countForFetchRequest:issuesNumberRequest error:nil];
[issuesNumberRequest release];
J'utilise à nouveau le managedObjectContext.
Mais quand je suis en train d'insérer un nouveau projet, application se bloque à la suite exception:
échec Assertion en - [UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-984.38/UITableView.m: 774 de terminaison de l'application en raison de uncaught exception « NSInternalInconsistencyException », motif: « mise à jour non valide: invalide nombre de lignes dans la section 0. le nombre de lignes contenues dans une section existante après la mise à jour (4) doit être égal au nombre de lignes contenues dans cette section avant la mise à jour (4), plus ou moins le nombre des lignes insérées ou supprimées de cette section (1 insérée, 0 effacée). '
Heureusement, j'ai trouvé une solution de contournement: si je crée et utilise NSManagedObjectContext séparée à l'intérieur du _configureCell: atIndexPath: application de la méthode ne plantera pas!
Je veux seulement savoir, ce comportement est-il correct ou pas?
Here is a sample project. Faites votre attention sur '_configureCell: atIndexPath:' et méthodes '_addSomeRows de CrashMeViewController de