2009-10-13 3 views
0

J'ai un NSFetchedResultsController comme source de données et j'implémente NSFetchedResultsControllerDelegate dans mon UITableViewController personnalisé. J'utilise sectionNameKeyPath pour diviser mon ensemble de résultats en plusieurs sections.Comment gérez-vous les insertions de section avec un NSFetchedResultsController?

Dans l'une de mes méthodes, j'ajoute un couple d'objets au contexte, tous dans une nouvelle section. Au moment où je sauvegarde les objets, les méthodes déléguées sont appelées correctement. L'ordre des événements:

// -controllerWillChangeContent: fires 
[self.tableView beginUpdates]; // I do this 

// -controller:didChangeSection:atIndex:forChangeType: fires for section insert 
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]]; 

// -controller:didChangeObject:atIndexPath:forChangeType:newIndexPath fires many times 
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
       withRowAnimation:UITavleViewRowAnimationFade]; // for each cell 

// -controllerDidChangeContent: fires after all of the inserts 
[self.tableView endUpdates]; // <--- Where things go terribly wrong!!! 

Le dernier appel, « endUpdates », l'application se bloque toujours:

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

Il semble que les mises à jour de la table ne sont pas en phase avec les données NSFetchedResultsController dans certains chemin, et les choses explosent. Je suis les docs sur NSFetchedResultsControllerDelegate, mais cela ne fonctionne pas. Quelle est la bonne façon de le faire?

MISE À JOUR: J'ai créé un projet de test qui présente ce bogue. Vous pouvez le télécharger à: NSBoom.zip

Répondre

1

Traçage à travers l'application, je note didChangeSection est appelée en premier, qui insère une section entière - et puis didChangeObject est appelé à plusieurs reprises. Le problème est que, dans didChangeSection, vous insérez une section entière, juste après la mise à jour de la vue de table, vous ajoutez des objets à cette même section. C'est essentiellement un cas de chevauchement des mises à jour ... (non autorisé même dans un bloc de mises à jour début/fin).

Si vous commentez l'insert d'objet individuel, tout cela fonctionne:

case NSFetchedResultsChangeInsert: 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

Si vous commentez l'insert section :, il ne fonctionne pas - mais je l'ai eu moins de chance avec insertRowsInSections travaillant tous les C'est peut-être parce qu'il n'y a pas encore de section (ce qui, je suis sûr, c'est pourquoi vous avez inséré la section pour commencer). Vous devrez peut-être détecter l'un ou l'autre cas pour faire des insertions avec la bonne granularité.

En général, j'ai eu beaucoup plus de chance de recharger et d'insérer des sections entières que des lignes, la vue de la table me semble très délicate autour de ceux qui travaillent. Vous pouvez également essayer UITableViewRowAnimationNone qui semble fonctionner plus souvent avec succès.

+0

Merci! Cette observation (les doubles mises à jour) m'a permis de trouver une solution de contournement que je peux utiliser. –

0

J'ai le même problème. Je trouve que didChangeSection se déclenche deux fois. Une fois lorsque vous créez l'objet à insérer, et une fois lorsque vous l'enregistrez réellement. Pour moi, il ne devrait pas appeler didChangeSection tant que save n'est pas appelé. Ou, à tout le moins, willChangeSection sera appelé lors de la création de l'objet, et didChangeSection sera appelé lorsqu'il sera enregistré.

Maintenant j'examine la méthode d'observation NSManagedObjectContextDidSaveNotification. Cela ne fait pas partie du protocole NSFetchedResultsControllerDelegate, mais vous pouvez vous inscrire pour le recevoir. Peut-être que cela ne sera appelé que lorsque j'appelle sauver et pas avant.

Questions connexes