2010-05-29 7 views
1

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

Répondre