Échec d'assertion dans - [UITableView _endCellAnimationsWithContext:]

89

Espérons que ce sera une solution rapide. J'ai essayé de comprendre l'erreur que je continue à obtenir. L'erreur est répertoriée ci-dessous et l'appdelagate est en dessous.

Toute aide est appréciée.

Merci

2012-04-12 21: 11: 52.669 Chanda [75100: f803] --- Échec d'assertion dans -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037 2012-04-12 21: 11: 52.671 Chanda [75100: f803] --- Arrêt de l'application en raison d'une exception non interceptée ' NSInternalInconsistencyException' , raison: 'Mise à jour non valide: nombre de lignes non valide dans la section 0. Le nombre de lignes contenues dans une section existante après la mise à jour (2) doit être égal au nombre de lignes contenues dans cette section avant la mise à jour (2), plus ou moins le nombre de lignes insérées ou supprimées de cette section (1 insérée, 0 supprimée) et plus ou moins le nombre de lignes déplacées dans ou hors de cette section (0 déplacées vers l'intérieur, 0 déplacées vers l'extérieur). »

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize databaseName,databasePath; 

- (BOOL)application: (UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
    self.databaseName = @"Customers.db";

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDir = [documentPaths objectAtIndex:0];
    self.databasePath = [documentDir stringByAppendingPathComponent:self.databaseName];
    [self createAndCheckDatabase];

    return YES;
}

- (void)createAndCheckDatabase {
    BOOL success;

    NSFileManager *fileManager = [NSFileManager defaultManager];
    success = [fileManager fileExistsAtPath:databasePath];

    if (success) return; 

    NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseName];

    [fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}

@end
Plongée sous-marine
la source
3
Vous devriez déplacer ce code vers les classes et probablement l'exécuter dans un thread d'arrière-plan. Quoi qu'il en soit, cette erreur se produit généralement lorsque vous essayez de supprimer des lignes sans réduire réellement le nombre de lignes fourni par la source de données de la vue table. Supprimez-vous réellement des données lorsque vous supprimez les lignes? Si vous ne supprimez aucune ligne, pouvez-vous fournir votre implémentation de source de données de vue de table?
Constantino Tsarouhas

Réponses:

43

Je ne vois pas la raison pour laquelle vous nous montrez cette partie du code. Votre erreur doit être liée à cette partie de votre code, je suppose

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

Vous faites probablement une erreur dans l'une de ces méthodes de source de données. Actuellement, il est impossible de dire ce qui ne va pas exactement, mais je suppose que cela pourrait être quelque chose comme: Vous indiquez à la vue de table dans le que numberOfRowsInSectionvous souhaitez avoir n lignes réservées et configurées et dans le cellForRowAtIndexPathvous ne gérez alors que n - 1 lignes par exemple.

Désolé que cette réponse ne puisse pas être aussi précise qu'elle devrait l'être. Si vous nous montrez votre implémentation de votre source de données, il serait beaucoup plus facile de savoir ce qui se passe.

pbx
la source
26

Comme Sun Tzu dit : il est préférable de gagner sans combattre . Dans mon cas, chaque fois que je vois ce genre de message d'erreur (c'est-à-dire que la différence entre les lignes ajoutées est supprimée, etc.) .. Je ne débogue même rien .. J'évite simplement de faire cet appel supplémentaire où je recharge les lignes etc. c'est 99% de les cas où cette erreur se produit.

C'est un scénario courant où ce bogue se produit: j'ai un UINavigationControlleret il a un UITableView, quand je clique sur une ligne, il pousse un nouveau UITableViewet ainsi de suite. Cette erreur m'arrive toujours lorsque je saute le dernier UITableviewet que je reviens à l' UITableViewavant, à ce stade, je fais un appel inutile à la loadItfonction qui insère essentiellement les lignes et relance le fichier UITableView.

La raison pour laquelle cela se produit est que je place par erreur ma fonction loadIt viewDidAppear:animatedplutôt que viewDidLoad. viewDidAppear:animatedest appelé à chaque fois que le UITableViewest affiché, viewDidLoadn'est appelé qu'une seule fois.

abbood
la source
3
Merci, bien dit. Votre premier paragraphe m'a mis sur la bonne voie pour résoudre un problème similaire.
scrrr
2
c'est mon plaisir @scrrr :)
abbood
Cela a changé ma façon de voir les choses - cela a résolu le problème en le rendant hors de propos. Tu gères!
Charlie
Félicitations à viewDidAppear plutôt qu'à viewDidLoad. C'était exactement mon problème et je l'ai traité pendant des semaines.
GrandSteph
1
J'ai imprimé votre citation Sun Tzu et l'ai collée en haut de mon écran. Merci pour la citation et pour m'aider à trouver une tonne de code redondant :)
Adrian
24

Lorsque vous supprimez des lignes, n'oubliez pas qu'il vérifie également les sections lors de la mise à jour, dans:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView

Si vous souhaitez supprimer une ligne qui est le dernier élément d'une section, vous devez supprimer la section entière à la place (sinon, le nombre de sections peut être erroné et lever cette exception).

Olof_t
la source
1
C'est de l'or massif! Clou frappé sur la tête! Exactement mon problème.
phatmann
6

N'oubliez pas de mettre à jour votre tableau qui détermine numberOfRowsInSection. Il doit être mis à jour avant de l'animer et de le supprimer

Nous vérifions si le nombre de lignes dans la section est de 1 car nous devrons supprimer la section entière.

Corrigez-moi si quelqu'un peut clarifier cette réponse.

[self.tableView beginUpdates];
if ([tableView numberOfRowsInSection:indexPath.section] == 1) {

   [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
} else {

   [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
[self.tableView endUpdates];
love2script12
la source
4

Je mets chaque élément de section dans des tableaux séparés. Mettez-les ensuite dans un autre tableau (arrayWithArray). Ma solution ici pour ce problème:

[quarantineMessages removeObject : message];
[_tableView beginUpdates];
if([[arrayWithArray objectAtIndex: indPath.section] count]  > 1)
{
    [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indPath] withRowAnimation:UITableViewRowAnimationBottom];
}
else
{
    [_tableView deleteSections:[NSIndexSet indexSetWithIndex:indPath.section]
              withRowAnimation:UITableViewRowAnimationFade];
}
[_tableView endUpdates];
Bob
la source
1
pour moi, ce sont les mises à jour de début et de fin qui l'ont résolu, merci!
Mark W
2
Je ne savais pas que la section devenait vide et la nécessité de l'animer à la place ... Merde! Merci!
dvkch
1
J'ai obtenu mon code pour fonctionner avec beaucoup d'aide de cette réponse. L'afficher ci-dessous.
love2script12
2

J'ai eu la même erreur.

J'utilisais les lignes suivantes

UINib *myCustomCellNib = [UINib nibWithNibName:@"CustomNib" bundle:nil];
[tableView registerNib:myCustomCellNib forCellReuseIdentifier:@"CustomNib"];

pour enregistrer la pointe dans la méthode viewDidLoad, car j'avais une pointe différente qui était également associée à la même classe. Par conséquent, la ligne

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GBFBLoadingCell"];

retournait nul sauf si j'ai enregistré la plume dans viewDidLoad.

Mon problème était que j'avais oublié de définir l'identifiant dans l'inspecteur d'attributs pour mon fichier "CustomNib.xib" et "CustomNib ~ iphone.xib". (Ou plus précisément, j'ai oublié d'appuyer sur Entrée après avoir tapé l'identifiant dans l'inspecteur d'attributs dans XCode, de sorte que le nouveau nom n'a pas pu être enregistré.)

J'espère que cela t'aides.

user1612868
la source
2
Je ne pense PAS que votre réponse ait un rapport avec le problème.
DawnSong
2

Si vous utilisez un NSFetchedResultsControllercomme moi et mettez à jour des données dans un fil d'arrière-plan, n'oubliez pas de commencer et de terminer les mises à jour dans le délégué:

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

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

J'ai eu la même erreur, qui en essayant avec [tableView reloadData]fonctionnait bien. L'erreur était en fait dans la ligne

[TabView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationRight];

Quand j'ai essayé de vérifier les valeurs d'indexPath, elles n'étaient pas correctes comme requis.

Je l'ai corrigé en modifiant les valeurs dans indexPathsArray.

J'espère que cela t'aides .

user5553647
la source
1

Cela pourrait être l'une des UITableViewDataSourceméthodes de protocole

Pour

- tableView:numberOfRowsInSection:

il doit renvoyer un entier égal à la somme ou au résultat de

-insertRowsAtIndexPaths:withRowAnimation:et / ou -deleteRowsAtIndexPaths:withRowAnimation:

Pour

- numberOfSectionsInTableView:

il doit renvoyer un entier égal à la somme ou au résultat de

-insertRowsAtIndexPaths:withRowAnimation: et / ou -deleteSections:withRowAnimation:

Ted
la source
0

J'ai eu le même problème avec une base de données de base. Si vous utilisez plusieurs FRC, il vous suffit de recharger la tableview à l'intérieur de chaque condition dans numberOfSectionsInTableView.

Privatus Privatus
la source
2
J'ai également ce problème avec les données de base. Pouvez-vous s'il vous plaît élaborer sur votre recette.
Drux
0

Cela m'est arrivé lors de l'utilisation de Swift et d'un magasin de données soutenu par FRC pour gérer les informations. L'ajout d'une simple vérification à l'opération de suppression pour évaluer la section indexPath.section actuelle m'a permis d'éviter un appel superflu. Je pense que je comprends pourquoi ce problème se produit ... Fondamentalement, je charge un message dans la ligne supérieure chaque fois que mon ensemble de données est vide. Cela crée un problème d'un seul coup car il y a une fausse ligne.

Ma solution

... delete my entity, save the datastore and call reloadData on tableView
//next I add this simple check to avoid calling deleteRows when the system (wrongly) determines that there is no section.

       if indexPath.section > 0 {

        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .None)

            }
Tommie C.
la source
0

Vérifiez simplement que vous appelez [yourTableView reloadData]; après modifier le tableau de valeurs.

Evgeniy Kleban
la source