Assertionsfehler in - [UITableView _endCellAnimationsWithContext:]

89

Hoffentlich ist dies eine schnelle Lösung. Ich habe versucht, den Fehler herauszufinden, den ich immer wieder bekomme. Der Fehler ist unten aufgeführt und die Appdelagate ist darunter.

Jede Hilfe wird geschätzt.

Vielen Dank

2012-04-12 21: 11: 52.669 Chanda [75100: f803] --- Assertionsfehler in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037 2012-04-12 21: 11: 52.671 Chanda [75100: f803] --- Beenden der App aufgrund einer nicht erfassten Ausnahme ' NSInternalInconsistencyException' , Grund: 'Ungültige Aktualisierung: Ungültige Anzahl von Zeilen in Abschnitt 0. Die Anzahl der Zeilen, die in einem vorhandenen Abschnitt nach der Aktualisierung enthalten sind (2), muss der Anzahl der Zeilen entsprechen, die in diesem Abschnitt vor der Aktualisierung enthalten sind (2), plus oder abzüglich der Anzahl der in diesen Abschnitt eingefügten oder gelöschten Zeilen (1 eingefügt, 0 gelöscht) und plus oder minus der Anzahl der in diesen Abschnitt oder aus diesem Abschnitt verschobenen Zeilen (0 eingezogen, 0 ausgezogen). "

#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
Scubadivingfool
quelle
3
Sie sollten diesen Code in Klassen verschieben und ihn wahrscheinlich in einem Hintergrundthread ausführen. Dieser Fehler tritt jedoch normalerweise auf, wenn Sie versuchen, Zeilen zu entfernen, ohne die Anzahl der Zeilen zu verringern, die von der Datenquelle der Tabellenansicht bereitgestellt werden. Entfernen Sie tatsächlich Daten, wenn Sie die Zeilen entfernen? Wenn Sie keine Zeilen löschen, können Sie die Implementierung Ihrer Datenquelle für die Tabellenansicht bereitstellen?
Constantino Tsarouhas

Antworten:

43

Ich sehe keinen Grund für Sie, uns diesen Teil des Codes zu zeigen. Ihr Fehler muss mit diesem Teil in Ihrem Code verbunden sein, nehme ich an

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

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

Wahrscheinlich machen Sie einen Fehler bei einer dieser Datenquellenmethoden. Derzeit ist es unmöglich zu sagen, was genau falsch ist, aber ich gehe davon aus, dass es ungefähr so ​​aussehen könnte: Sie sagen der Tabellenansicht numberOfRowsInSection, dass Sie n Zeilen reservieren und einrichten möchten und dass cellForRowAtIndexPathSie dann beispielsweise nur n - 1 Zeilen behandeln.

Entschuldigung, dass diese Antwort nicht so präzise sein kann, wie sie sein sollte. Wenn Sie uns Ihre Implementierung Ihrer Datenquelle zeigen, ist es viel einfacher zu sagen, was los ist.

pbx
quelle
26

Wie Sun Tzu sagte : Es ist am besten, ohne zu kämpfen zu gewinnen . In meinem Fall, wenn ich diese Art von Fehlermeldung sehe (dh Diskrepanz zwischen hinzugefügten, gelöschten Zeilen usw.). Ich debugge nicht einmal etwas. Ich vermeide einfach diesen zusätzlichen Aufruf, bei dem ich die Zeilen neu lade usw. Das sind 99% von die Fälle, in denen dieser Fehler auftritt.

Dies ist ein häufiges Szenario, in dem dieser Fehler auftritt: Ich habe ein UINavigationControllerund es hat ein UITableView, wenn ich auf eine Zeile klicke, wird ein neues gesendet UITableViewund so weiter. Dieser Fehler tritt immer zu mir , als ich die letzten Pop UITableviewund die zurückgehen , UITableViewbevor es an dieser Stelle ich zur einem unnötigen Anruf - loadItFunktion , die im Grunde die Zeilen einfügt und relaods die UITableView.

Der Grund , warum dies passiert ist , weil ich meine loadit Funktion fälschlicherweise setzen in viewDidAppear:animatedstatt viewDidLoad. viewDidAppear:animatedwird jedes Mal aufgerufen, wenn das UITableViewangezeigt wird, viewDidLoadwird nur einmal aufgerufen.

Abbood
quelle
3
Danke, gut gesagt. Ihr erster Absatz hat mich auf den richtigen Weg gebracht, um ein ähnliches Problem zu lösen.
Scrrr
2
Es ist mir ein Vergnügen @scrrr :)
Abbood
Dies änderte meine Sichtweise - es behebt das Problem, indem es irrelevant wird. Du rockst!
Charlie
Ein großes Lob an viewDidAppear und nicht an viewDidLoad. Das war genau mein Problem und ich beschäftigte mich wochenlang damit.
GrandSteph
1
Ich druckte Ihr Sun Tzu-Zitat aus und klebte es oben auf meinen Bildschirm. Vielen Dank für das Zitat und helfen mir bei der Suche nach einer Menge redundanten Codes :)
Adrian
24

Denken Sie beim Entfernen von Zeilen daran, dass beim Aktualisieren auch Abschnitte überprüft werden:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView

Wenn Sie eine Zeile entfernen möchten, die das letzte Element in einem Abschnitt ist, müssen Sie stattdessen den gesamten Abschnitt entfernen (andernfalls kann die Anzahl der Abschnitte falsch sein und diese Ausnahme auslösen).

Olof_t
quelle
1
Das ist massives Gold! Nagel auf den Kopf getroffen! Genau mein Problem.
Phatmann
6

Vergessen Sie nicht, Ihr Array zu aktualisieren, das numberOfRowsInSection bestimmt. Es muss aktualisiert werden, bevor Sie animieren und entfernen

Wir prüfen, ob die Anzahl der Zeilen im Abschnitt 1 ist, da wir den gesamten Abschnitt löschen müssen.

Korrigieren Sie mich, wenn jemand diese Antwort klarer machen kann.

[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
quelle
4

Ich habe jedes Abschnittselement in separate Arrays eingefügt. Fügen Sie sie dann in ein anderes Array (arrayWithArray) ein. Meine Lösung hier für dieses Problem:

[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
quelle
1
Für mich waren es die Anfangs- und Endaktualisierungen, die das Problem gelöst haben, danke!
Mark W
2
Ich wusste nicht, dass der Abschnitt leer wird und stattdessen animiert werden muss ... Verdammt! Vielen Dank!
dvkch
1
Ich habe meinen Code dazu gebracht, mit viel Hilfe von dieser Antwort zu arbeiten. Poste es unten.
love2script12
2

Ich hatte den gleichen Fehler.

Ich habe die folgenden Zeilen verwendet

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

um die Feder in der viewDidLoad-Methode zu registrieren, da ich eine andere Feder hatte, die ebenfalls derselben Klasse zugeordnet war. Daher die Linie

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

gab nil zurück, es sei denn, ich habe die Feder in viewDidLoad registriert.

Mein Problem war, dass ich vergessen habe, den Bezeichner im Attributinspektor für meine Dateien "CustomNib.xib" und "CustomNib ~ iphone.xib" festzulegen. (Oder genauer gesagt, ich habe vergessen, die Eingabetaste zu drücken, nachdem ich den Bezeichner im Attributinspektor in XCode eingegeben habe, sodass der neue Name nicht gespeichert werden konnte.)

Hoffe das hilft.

user1612868
quelle
2
Ich glaube NICHT, dass Ihre Antwort einen Bezug zum Thema hat.
DawnSong
2

Wenn Sie ein NSFetchedResultsControllerLike wie ich verwenden und Daten in einem Hintergrundthread aktualisieren, vergessen Sie nicht, Aktualisierungen im Delegaten zu beginnen und zu beenden:

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

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

Ich hatte den gleichen Fehler, der beim Ausprobieren gut [tableView reloadData]funktionierte. Der Fehler war tatsächlich in der Leitung

[TabView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationRight];

Als ich versuchte, die indexPath-Werte zu überprüfen, waren sie nicht wie erforderlich korrekt.

Ich habe es behoben, indem ich Werte in geändert habe indexPathsArray.

Hoffe das hilft .

user5553647
quelle
1

Es könnte eine der UITableViewDataSourceProtokollmethoden sein

Zum

- tableView:numberOfRowsInSection:

es sollte eine ganze Zahl zurückgeben, die der Summe oder dem Ergebnis von entspricht

-insertRowsAtIndexPaths:withRowAnimation:und / oder -deleteRowsAtIndexPaths:withRowAnimation:

Zum

- numberOfSectionsInTableView:

es sollte eine ganze Zahl zurückgeben, die der Summe oder dem Ergebnis von entspricht

-insertRowsAtIndexPaths:withRowAnimation: und / oder -deleteSections:withRowAnimation:

Ted
quelle
0

Ich hatte das gleiche Problem mit einer Kerndatenbank. Wenn Sie viele FRC verwenden, müssen Sie nur die Tabellenansicht in jeder Bedingung in numberOfSectionsInTableView neu laden.

Privatus Privatus
quelle
2
Ich habe auch dieses Problem mit Core Data. Können Sie bitte Ihr Rezept näher erläutern?
Drux
0

Dies ist mir gerade passiert, als ich Swift und einen von FRC unterstützten Datenspeicher zum Verwalten von Informationen verwendet habe. Durch Hinzufügen einer einfachen Prüfung zum Löschvorgang zur Auswertung des aktuellen indexPath.section konnte ich einen externen Aufruf vermeiden. Ich glaube, ich verstehe, warum dieses Problem auftritt ... Grundsätzlich lade ich eine Nachricht in die oberste Zeile, wenn mein Datensatz leer ist. Dies führt zu einem Off-by-One-Problem, da es eine Faux-Reihe gibt.

Meine Lösung

... 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.
quelle
0

Überprüfen Sie einfach, ob Sie [yourTableView reloadData] aufrufen. nach dem Ändern des Array von Werten.

Evgeniy Kleban
quelle