Errore di asserzione in - [UITableView _endCellAnimationsWithContext:]


89

Si spera che questa sia una soluzione rapida. Ho cercato di capire l'errore che continuo a ricevere. L'errore è elencato di seguito e l'appdelagate è sotto.

Qualsiasi aiuto è apprezzato.

Grazie

2012-04-12 21: 11: 52.669 Chanda [75100: f803] --- Asserzione non riuscita in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037 2012-04-12 21: 11: 52.671 Chanda [75100: f803] --- Chiusura dell'app a causa di un'eccezione non rilevata ' NSInternalInconsistencyException' , motivo: "Aggiornamento non valido: numero di righe non valido nella sezione 0. Il numero di righe contenute in una sezione esistente dopo l'aggiornamento (2) deve essere uguale al numero di righe contenute in quella sezione prima dell'aggiornamento (2), più o meno il numero di righe inserite o eliminate da quella sezione (1 inserita, 0 eliminata) e più o meno il numero di righe spostate all'interno o all'esterno di quella sezione (0 spostate all'interno, 0 spostate fuori). "

#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

3
Dovresti spostare quel codice nelle classi e probabilmente eseguirlo in un thread in background. Ad ogni modo, questo errore si verifica in genere quando si tenta di rimuovere righe senza effettivamente diminuire il numero di righe fornito dall'origine dati della vista tabella. Stai effettivamente rimuovendo i dati quando rimuovi le righe? Se non elimini alcuna riga, puoi fornire l'implementazione dell'origine dati della visualizzazione tabella?
Constantino Tsarouhas

Risposte:


43

Non vedo il motivo per cui ci mostri questa parte del codice. Il tuo errore deve essere collegato a questa parte nel tuo codice presumo

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

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

Probabilmente stai commettendo un errore in uno di questi metodi di origine dati. Al momento è impossibile dire cosa sia esattamente sbagliato, ma presumo che potrebbe essere qualcosa del tipo: stai dicendo alla vista tabella in numberOfRowsInSectionche vorresti avere n righe riservate e impostate e in cellForRowAtIndexPathquindi gestisci solo n - 1 righe per esempio.

Mi dispiace che questa risposta non possa essere precisa come dovrebbe essere. Se ci mostri la tua implementazione della tua origine dati, sarebbe molto più facile dire cosa sta succedendo.


26

Come ha detto Sun Tzu : è meglio vincere senza combattere . Nel mio caso ogni volta che vedo questo tipo di messaggio di errore (cioè discrepanza tra le righe aggiunte cancellate ecc.) .. Non eseguo nemmeno il debug di nulla .. Evito semplicemente di fare quella chiamata extra in cui ricarico le righe ecc. Che è il 99% del i casi in cui si verifica questo errore.

Questo è uno scenario comune in cui si verifica questo bug: ho un UINavigationControllere ha un UITableView, quando clicco su una riga ne preme uno nuovo UITableViewe così via. Questo errore mi capita sempre quando apro l'ultimo UITableviewe torno al UITableViewprecedente, a questo punto faccio una chiamata inutile alla loadItfunzione che sostanzialmente inserisce le righe e ricarica il file UITableView.

Il motivo per cui ciò accade è perché inserisco erroneamente la mia funzione loadIt viewDidAppear:animatedanziché viewDidLoad. viewDidAppear:animatedviene chiamato ogni volta che UITableViewviene visualizzato, viewDidLoadviene chiamato solo una volta.


3
Grazie, ben detto. Il tuo primo paragrafo mi ha messo sulla strada giusta per risolvere un problema simile.
scrrr

2
è un piacere @scrrr :)
abbood

Questo ha cambiato il modo in cui lo vedevo: ha risolto il problema rendendolo irrilevante. Sei forte!
Charlie,

Complimenti a viewDidAppear piuttosto che a viewDidLoad. Quello era esattamente il mio problema e l'ho affrontato per settimane.
GrandSteph

1
Ho stampato la tua citazione di Sun Tzu e l'ho incollata sulla parte superiore dello schermo. Grazie per la citazione e per avermi aiutato a trovare un sacco di codice ridondante :)
Adrian

24

Quando rimuovi le righe, ricorda che controlla anche le sezioni durante l'aggiornamento, in:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView

Se si desidera rimuovere una riga che è l'ultimo elemento di una sezione, è necessario rimuovere l'intera sezione (altrimenti il ​​conteggio delle sezioni potrebbe essere errato e generare questa eccezione).


1
Questo è oro massiccio! Colpo di chiodo in testa! Esattamente il mio problema.
phatmann

6

Non dimenticare di aggiornare il tuo array che determina numberOfRowsInSection. Deve essere aggiornato prima di animare e rimuovere

Controlliamo se il numero di righe nella sezione è 1 perché dovremo eliminare l'intera sezione.

Correggimi se qualcuno può rendere più chiara questa risposta.

[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];

4

Metto ogni elemento della sezione in array separati. Quindi inseriscili in un altro array (arrayWithArray). La mia soluzione qui per questo problema:

[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];

1
per me sono stati gli aggiornamenti di inizio e fine a risolverlo, grazie!
Mark W

2
Non lo sapevo della sezione che diventava vuota e della necessità invece di animarla ... Dannazione! Grazie!
dvkch

1
Ho ottenuto il mio codice per funzionare con molto aiuto da questa risposta. Inserendolo di seguito.
love2script12

2

Ho avuto lo stesso errore.

Stavo usando le seguenti righe

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

per registrare il pennino nel metodo viewDidLoad, poiché avevo un pennino diverso che era anche associato alla stessa classe. Quindi, la linea

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

restituiva zero a meno che non avessi registrato il pennino in viewDidLoad.

Il mio problema era che ho dimenticato di impostare l'identificatore nell'ispettore degli attributi per il mio file "CustomNib.xib" e "CustomNib ~ iphone.xib". (O più precisamente, che ho dimenticato di premere Invio dopo aver digitato l'identificatore nell'ispettore degli attributi in XCode, in modo che il nuovo nome non sia riuscito a salvare.)

Spero che questo ti aiuti.


2
NON penso che la tua risposta abbia relazione con il problema.
DawnSong,

2

Se stai usando un NSFetchedResultsControllercome me e stai aggiornando i dati in un thread in background, non dimenticare di iniziare e terminare gli aggiornamenti nel delegato:

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

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

2

Ho avuto lo stesso errore, che durante il tentativo con [tableView reloadData]funzionava bene. L'errore era effettivamente nella linea

[TabView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationRight];

Quando ho provato a controllare i valori indexPath, non erano corretti come richiesto.

L'ho risolto modificando i valori in indexPathsArray.

Spero che questo ti aiuti .


1

Potrebbe essere uno dei UITableViewDataSourcemetodi di protocollo

Per

- tableView:numberOfRowsInSection:

dovrebbe restituire un numero intero uguale alla somma o al risultato di

-insertRowsAtIndexPaths:withRowAnimation:e / o -deleteRowsAtIndexPaths:withRowAnimation:

Per

- numberOfSectionsInTableView:

dovrebbe restituire un numero intero uguale alla somma o al risultato di

-insertRowsAtIndexPaths:withRowAnimation: e / o -deleteSections:withRowAnimation:


0

Ho avuto lo stesso problema con un database principale. Se stai usando molti FRC, devi solo ricaricare la tableview all'interno di ogni condizione in numberOfSectionsInTableView.


2
Ho anche questo problema con Core Data. Puoi per favore elaborare la tua ricetta.
Drux

0

Mi è appena successo questo mentre usavo Swift e un archivio dati supportato da FRC per gestire le informazioni. L'aggiunta di un semplice segno di spunta all'operazione di cancellazione per valutare l'attuale indexPath.section mi ha permesso di evitare una chiamata estranea. Penso di capire perché si verifica questo problema ... Fondamentalmente carico un messaggio nella riga superiore ogni volta che il mio set di dati è vuoto. Questo crea un problema di un problema in quanto c'è una falsa riga.

La mia soluzione

... 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)

            }

0

Controlla semplicemente di chiamare [yourTableView reloadData]; dopo aver modificato l'array di valori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.