2010-08-13 5 views
4

je UITableViewController et mis en œuvre sous-classé les éléments suivantsUITableView Mise à jour fera exception

  1. NSFetchedResultsController avec ses délégués
  2. tableView:sectionForSectionIndexTitle:atIndex:
  3. tableView:titleForHeaderInSection:

Dans controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:

case NSFetchedResultsChangeMove: 
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
      withRowAnimation:UITableViewRowAnimationFade]; 
    [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
      withRowAnimation:UITableViewRowAnimationFade]; 
    break; 

Dans le modèle de données pour l'entité donnée, j'ai la propriété transitoire uppercaseFirstLetterOfName qui retournera la première lettre de la propriété persistante.

Ceci est tout pour atteindre des sections alphabétiques pour les éléments de table et l'index latéral.

Maintenant, si j'ai un seul enregistrement pour une section, puis je le renommer afin qu'il change la section, je reçois l'exception suivante, qui se produit quelque part après NSFetchedResultsChangeMove.

*** échec Assertion en - [UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-984.38/UITableView.m:774

Exception a été pris au cours du traitement du changement de base de données : mise à jour non valide: nombre incorrect de lignes dans la section 0. le nombre de lignes contenues dans une section existante après la mise à jour (1) doit être égal au nombre de lignes contenue dans cette section avant la mise à jour (1), plus ou moins le nombre de lignes insérées ou décalées té de cette section (0 inséré, 1 supprimé).

Des idées?

UPD un code plus:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    NSInteger count = [[fetchedResultsController sections] count]; 
    return count; 
} 

- (NSInteger)tableView:(UITableView *)tableView 
         numberOfRowsInSection:(NSInteger)section 
{ 
    NSInteger numberOfRows = 0; 
    if ([[fetchedResultsController sections] count] > 0) 
    { 
     id <NSFetchedResultsSectionInfo> sectionInfo = 
       [[fetchedResultsController sections] objectAtIndex:section]; 
     numberOfRows = [sectionInfo numberOfObjects]; 
    } 
    return numberOfRows; 
} 

...

NSSortDescriptor* sortByWordDescriptor = [[NSSortDescriptor alloc] 
         initWithKey:@"subject" ascending:YES]; 
    NSArray* sortArray = [[NSArray alloc] 
         initWithObjects:sortByWordDescriptor, nil]; 
    [fetchRequest setSortDescriptors:sortArray]; 

    NSFetchedResultsController* controller = [[NSFetchedResultsController alloc] 
         initWithFetchRequest:fetchRequest 
         managedObjectContext:managedObjectContext 
         sectionNameKeyPath:@"uppercaseFirstLetterOfName" 
         cacheName:@"Root"]; 

UPD (patché): Au moment où je patché le code comme ceci:

case NSFetchedResultsChangeMove: 
     NSUInteger tableSectionCount = [self.tableView numberOfSections]; 
     NSUInteger modelSectionCount = [[controller sections] count]; 
     if (modelSectionCount > tableSectionCount) 
     { 
      [self.tableView insertSections:[NSIndexSet 
           indexSetWithIndex:[newIndexPath section]] 
           withRowAnimation:UITableViewRowAnimationNone]; 
     } 
     else if(modelSectionCount < tableSectionCount) 
     { 
      if (tableSectionCount > 1) 
      { 
       [self.tableView deleteSections:[NSIndexSet 
           indexSetWithIndex:[indexPath section]] 
           withRowAnimation:UITableViewRowAnimationNone]; 
      } 
     } 
     [tableView deleteRowsAtIndexPaths:[NSArray 
           arrayWithObject:indexPath] 
           withRowAnimation:UITableViewRowAnimationFade]; 
     [tableView insertRowsAtIndexPaths:[NSArray 
           arrayWithObject:newIndexPath] 
           withRowAnimation:UITableViewRowAnimationFade]; 

     break; 

Alors pas de crash, mais cette solution est-elle correcte?

+0

Je suppose que 'NSFetchedResultsController' ne sait pas que la section est supprimée, car' contrôleur: didChangeSection: ... ' ne tire jamais. Mais comment gérer cela? – Pablo

+1

D'après les traces, après la modification de l'objet, le nombre de sections doit être réduit, en fait '[[sections extraites de sections récupérées] [' fetchedResultsController]] 'renvoie une ancienne valeur. Alors, comment mettre à jour le nombre de sections du contrôleur ou invalider la propriété transitoire? – Pablo

Répondre

0

Le code qui gère les sections s'attend à ce qu'un élément soit à un certain index mais cet élément n'est plus là et il ne semble pas que vous ayez codé pour ce scénario en retournant zéro lorsqu'il n'y a aucun élément.

+0

Pourriez-vous s'il vous plaît être plus précis? Quel code va-t-on attendre, le mien ou le framework? Où devrais-je retourner zéro? – Pablo

0

vous devez modifier le tableau de sources de données avant d'insérer ou de supprimer une méthode de tableView!

[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
     withRowAnimation:UITableViewRowAnimationFade]; 
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
     withRowAnimation:UITableViewRowAnimationFade]; 

et NSFetchedResultsChangeMove devrait terminer votre action de mouvement d'interface utilisateur. donc ce que vous devez faire est de réorganiser les éléments datasorce.

+0

vérifier les codes de démonstration en direct ici: http://github.com/erica/iphone-3.0-cookbook-/blob/master/C11-Tables/13-Enabling%20Reordering/main.m – xhan

+0

Réorganiser les éléments de la source de données? Je ne suis pas sûr si je comprends comment je ferais cela. Dans ce contrôleur, je passe simplement un objet de 'fetchedResultsController' à un autre contrôleur de vue, où il est modifié et à ce moment les délégués de' NSFetchedResultsController' sont déclenchés. Les codes de démonstration n'utilisent pas 'NSFetchedResultsController', donc je ne peux pas comprendre ... – Pablo

+0

En fait, l'utilisation de' NSFetchedResultsController' fait d'abord des modifications de la source de données, puis appelle 'didChangeObject' pour mettre à jour la table de données. Toujours confus et à la recherche de solution. – Pablo

2

Je pense que je sais ce qui vous arrive.Assurez-vous que vous avez:

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

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

La documentation dit au sujet de méthode "beginUpdates":

Appelez cette méthode si vous voulez des insertions ultérieures, la suppression et les opérations de sélection (par exemple, cellForRowAtIndexPath: et indexPathsForVisibleRows) être animé simultanément.

qui est ce que vous faites avec:

[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 

Vive

Questions connexes