Błąd potwierdzenia w - [UITableView _endCellAnimationsWithContext:]

89

Miejmy nadzieję, że będzie to szybkie rozwiązanie. Próbowałem znaleźć błąd, który ciągle otrzymuję. Błąd jest wymieniony poniżej, a appdelagate znajduje się poniżej.

Każda pomoc jest mile widziana.

Dzięki

2012-04-12 21: 11: 52,669 Chanda [75100: f803] --- błąd potwierdzenia w -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037 2012-04-12 21: 11: 52,671 Chanda [75100: f803] --- zakończenie aplikacji ze względu nieprzechwyconego wyjątkiem ' NSInternalInconsistencyException' , powód: „Nieprawidłowa aktualizacja: nieprawidłowa liczba wierszy w sekcji 0. Liczba wierszy zawartych w istniejącej sekcji po aktualizacji (2) musi być równa liczbie wierszy zawartych w tej sekcji przed aktualizacją (2), plus lub minus liczba wierszy wstawionych lub usuniętych z tej sekcji (1 wstawiono, 0 usuniętych) i plus lub minus liczba wierszy przeniesionych do lub z tej sekcji (0 przeniesionych, 0 usuniętych) ”.

#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
źródło
3
Powinieneś przenieść ten kod do klas i prawdopodobnie wykonać go w wątku w tle. W każdym razie ten błąd zwykle pojawia się, gdy próbujesz usunąć wiersze bez faktycznego zmniejszenia liczby wierszy podanej przez źródło danych widoku tabeli. Czy faktycznie usuwasz dane podczas usuwania wierszy? Jeśli nie usuwasz żadnych wierszy, czy możesz podać implementację źródła danych widoku tabeli?
Constantino Tsarouhas

Odpowiedzi:

43

Nie widzę powodu, dla którego chcesz nam pokazać tę część kodu. Twój błąd musi być powiązany z tą częścią twojego kodu, jak zakładam

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

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

Prawdopodobnie popełniasz błąd w jednej z tych metod źródła danych. Obecnie nie można powiedzieć, co dokładnie jest nie tak, ale przypuszczam, że może to być coś takiego: Mówisz, że widok tabeli w tym numberOfRowsInSection, że chciałbyś mieć zarezerwowane i skonfigurowane n wierszy, a cellForRowAtIndexPathnastępnie obsługujesz tylko na przykład n - 1 wierszy.

Przepraszam, że ta odpowiedź nie może być tak precyzyjna, jak powinna. Jeśli pokażesz nam swoją implementację źródła danych, znacznie łatwiej będzie stwierdzić, co się dzieje.

pbx
źródło
26

Jak powiedział Sun Tzu : najlepiej wygrywać bez walki . W moim przypadku za każdym razem, gdy widzę tego rodzaju komunikat o błędzie (np. Rozbieżność między dodanymi wierszami usuniętymi itp.) .. Nawet nie debuguję niczego .. Po prostu unikam wykonywania dodatkowego wywołania, w którym ponownie ładuję wiersze itp. To 99% przypadki, w których występuje ten błąd.

Jest to typowy scenariusz, w którym występuje ten błąd: mam a UINavigationControlleri ma UITableView, kiedy klikam wiersz, wypycha nowy UITableViewi tak dalej. Ten błąd zawsze mi się przytrafia, kiedy wyskakuję ostatni UITableviewi wracam do UITableViewpoprzedniego, w tym momencie loadItwykonuję niepotrzebne wywołanie funkcji, która w zasadzie wstawia wiersze i ponownie włącza UITableView.

Powodem tego jest to, że błędnie umieściłem funkcję loadIt w viewDidAppear:animatedzamiast viewDidLoad. viewDidAppear:animatedjest wywoływana za każdym razem, gdy UITableViewjest wyświetlany, viewDidLoadjest wywoływana tylko raz.

abbood
źródło
3
Dzięki, dobrze powiedziane. Twój pierwszy akapit skierował mnie na właściwą drogę do rozwiązania podobnego problemu.
scrrr
2
It's my pleasure @scrrr :)
abbood
To zmieniło sposób, w jaki na to patrzyłem - rozwiązało problem, czyniąc go nieistotnym. Rządzisz!
Charlie
Uznanie za viewDidAppear zamiast viewDidLoad. To był dokładnie mój problem i zajmowałem się nim tygodniami.
GrandSteph
1
Wydrukowałem Twój cytat z Sun Tzu i przykleiłem go taśmą do górnej części ekranu. Dziękuję za wycenę i pomoc w znalezieniu mnóstwa zbędnego kodu :)
Adrian,
24

Podczas usuwania wierszy pamiętaj, że podczas aktualizacji sprawdza również sekcje w:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView

Jeśli chcesz usunąć wiersz, który jest ostatnim elementem w sekcji, musisz zamiast tego usunąć całą sekcję (w przeciwnym razie może to spowodować błędną liczbę sekcji i zgłosić ten wyjątek).

Olof_t
źródło
1
To jest solidne złoto! Paznokieć uderzył w głowę! Dokładnie mój problem.
phatmann
6

Nie zapomnij zaktualizować swojej tablicy, która określa numberOfRowsInSection. Musi zostać zaktualizowany przed animacją i usunięciem

Sprawdzamy, czy liczba wierszy w sekcji wynosi 1, ponieważ będziemy musieli usunąć całą sekcję.

Popraw mnie, jeśli ktoś może wyjaśnić tę odpowiedź.

[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
źródło
4

Każdy element sekcji umieszczam w oddzielnych tablicach. Następnie umieść je w innej tablicy (arrayWithArray). Moje rozwiązanie tego problemu:

[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];
Pion
źródło
1
dla mnie to były początkowe i końcowe aktualizacje, które go rozwiązały, dzięki!
Mark W,
2
Nie wiedziałem o tym, że sekcja stała się pusta i trzeba ją ożywić ... Cholera! dzięki!
dvkch
1
Mam mój kod do pracy z dużą pomocą tej odpowiedzi. Publikuję to poniżej.
love2script12
2

Miałem ten sam błąd.

Używałem następujących linii

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

zarejestrować końcówkę w metodzie viewDidLoad, ponieważ miałem inną końcówkę, która była również powiązana z tą samą klasą. Stąd linia

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

zwracał nil, chyba że zarejestrowałem końcówkę w pliku viewDidLoad.

Mój problem polegał na tym, że zapomniałem ustawić identyfikator w inspektorze atrybutów dla mojego pliku „CustomNib.xib” i „CustomNib ~ iphone.xib”. (A dokładniej, że zapomniałem nacisnąć klawisz Enter po wpisaniu identyfikatora w inspektorze atrybutów w XCode, przez co nie udało się zapisać nowej nazwy).

Mam nadzieję że to pomoże.

user1612868
źródło
2
Nie sądzę, że twoja odpowiedź ma związek z problemem.
DawnSong
2

Jeśli używasz NSFetchedResultsControllerpodobnego do mnie i aktualizujesz dane w wątku w tle, nie zapomnij o rozpoczęciu i zakończeniu aktualizacji w pełnomocniku:

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

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}
mikeho
źródło
2

Miałem ten sam błąd, który podczas próby [tableView reloadData]działał dobrze. Błąd faktycznie tkwił w linii

[TabView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationRight];

Kiedy próbowałem sprawdzić wartości indexPath, nie były one poprawne zgodnie z wymaganiami.

Naprawiłem to, zmieniając wartości w indexPathsArray.

Mam nadzieję że to pomoże .

user5553647
źródło
1

To może być jedna z UITableViewDataSourcemetod protokołu

Dla

- tableView:numberOfRowsInSection:

powinien zwrócić liczbę całkowitą równą sumie lub wynikowi funkcji

-insertRowsAtIndexPaths:withRowAnimation:i / lub -deleteRowsAtIndexPaths:withRowAnimation:

Dla

- numberOfSectionsInTableView:

powinien zwrócić liczbę całkowitą równą sumie lub wynikowi funkcji

-insertRowsAtIndexPaths:withRowAnimation: i / lub -deleteSections:withRowAnimation:

Przetrząsać
źródło
0

Miałem ten sam problem z bazą danych podstawowych. Jeśli używasz wielu FRC, wystarczy ponownie załadować widok tabeli wewnątrz każdego warunku w numberOfSectionsInTableView.

Privatus Privatus
źródło
2
Mam również ten problem z danymi podstawowymi. Czy możesz rozwinąć swój przepis?
Drux
0

Właśnie to mi się przydarzyło, gdy korzystałem ze Swift i magazynu danych wspieranego przez FRC do zarządzania informacjami. Dodanie prostego sprawdzenia do operacji usuwania w celu oceny bieżącej indexPath.section pozwoliło mi uniknąć dodatkowego wywołania. Myślę, że rozumiem, dlaczego występuje ten problem ... Zasadniczo ładuję wiadomość do górnego wiersza, gdy mój zestaw danych jest pusty. Stwarza to odstępstwo o jeden problem, ponieważ istnieje fałszywy wiersz.

Moje rozwiązanie

... 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.
źródło
0

Po prostu sprawdź, czy wywołujesz [yourTableView reloadData]; po zmodyfikowaniu tablicy wartości.

Evgeniy Kleban
źródło