Помилка твердження в - [UITableView _endCellAnimationsWithContext:]


89

Сподіваємось, це буде швидким виправленням. Я намагався з'ясувати помилку, яку я постійно отримую. Помилка вказана нижче, а appdelagate - нижче.

Будь-яка допомога вдячна.

Дякую

2012-04-12 21: 11: 52.669 Chanda [75100: f803] --- Помилка твердження у -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037 2012-04-12 21: 11: 52.671 Chanda [75100: f803] --- Завершення програми через невпійманий виняток ' NSInternalInconsistencyException' , причина: 'Недійсне оновлення: недійсна кількість рядків у розділі 0. Кількість рядків, що містяться в існуючому розділі після оновлення (2), повинна дорівнювати кількості рядків, що містяться в цьому розділі до оновлення (2), плюс або мінус кількість рядків, вставлених або видалених з цього розділу (1 вставлено, 0 видалено) і плюс-мінус кількість рядків, переміщених у цей розділ або поза ним (0 переміщено, 0 переміщено). '

#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
Вам слід перемістити цей код до класів і, можливо, виконати його у фоновому потоці. У будь-якому випадку, ця помилка зазвичай виникає при спробі видалити рядки, не зменшуючи фактично кількість рядків, як це передбачено джерелом даних подання таблиці. Ви насправді видаляєте дані, коли видаляєте рядки? Якщо ви не видаляєте жодних рядків, чи можете ви надати реалізацію джерела даних для подання таблиці?
Костянтин Царухас,

Відповіді:


43

Я не бачу причини для того, щоб ви показували нам цю частину коду. Я вважаю, ваша помилка повинна бути пов’язана з цією частиною вашого коду

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

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

Можливо, ви допустили помилку в одному з цих методів джерела даних. В даний час неможливо сказати, що саме неправильно, але я припускаю, що це може бути щось на зразок: Ви повідомляєте подання таблиці в тому, що numberOfRowsInSectionви хочете, щоб було зарезервовано та налаштовано n рядків, а в тому випадку cellForRowAtIndexPathви обробляєте лише n - 1 рядки, наприклад.

Вибачте, що ця відповідь не може бути такою точною, якою вона повинна бути. Якщо ви покажете нам свою реалізацію джерела даних, було б набагато простіше сказати, що відбувається.


26

Як сказав Сунь Цзи : найкраще перемагати, не борючись . У моєму випадку всякий раз, коли я бачу такий тип повідомлення про помилку (тобто невідповідність між доданими рядками, видаленими тощо) .. Я навіть нічого не налагоджую .. Я просто уникаю цього додаткового дзвінка, де я перезавантажую рядки і т. Д. Це 99% від випадки, коли ця помилка трапляється.

Це поширений сценарій, коли трапляється ця помилка: у мене є UINavigationControllerі вона має UITableView, коли я натискаю на рядок, вона виштовхує нову UITableViewі так далі. Ця помилка завжди трапляється зі мною, коли я висуваю останнє UITableviewі повертаюся до UITableViewпопереднього, і в цей момент я роблю непотрібний виклик loadItфункції, яка в основному вставляє рядки та перекодує UITableView.

Причиною цього є те, що я помилково розміщую свою функцію loadIt viewDidAppear:animatedзамість viewDidLoad. viewDidAppear:animatedвикликається кожного разу, коли UITableViewвідображається, viewDidLoadвикликається лише один раз.


3
Дякую, добре сказано. Ваш перший абзац поставив мене на правильний шлях до вирішення подібної проблеми.
scrrr

2
мені приємно @scrrr :)
abbood

Ця зміна, як я на неї подивився, - вирішила проблему, зробивши її неактуальною. Ви рок!
Чарлі

Похвала для viewDidAppear, а не viewDidLoad. Це було саме моє питання, і я цим займався тижнями.
GrandSteph

1
Я надрукував вашу цитату з Сан-Цзи та проклеїв її у верхній частині екрану. Дякую за цитату та допомогу у пошуку тонни зайвого коду :)
Адріан

24

Видаляючи рядки, пам’ятайте, що він також перевіряє розділи під час оновлення в:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView

Якщо ви хочете видалити рядок, який є останнім елементом у розділі, вам потрібно натомість видалити весь розділ (інакше це може спричинити неправильний підрахунок розділів і викинути цей виняток).


1
Це тверде золото! Цвях вдарився по голові! Саме моє питання.
phatmann

6

Не забудьте оновити свій масив, який визначає numberOfRowsInSection. Його потрібно оновити перед тим, як анімувати та видалити

Ми перевіряємо, чи кількість рядків у розділі дорівнює 1, оскільки нам доведеться видалити весь розділ.

Виправте мене, якщо хтось зможе пояснити цю відповідь.

[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

Я розміщую елементи кожного розділу в окремих масивах. Потім помістіть їх в інший масив (arrayWithArray). Моє рішення цієї проблеми:

[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
для мене це почали та закінчували оновлення, які вирішили це, дякую!
Mark W

2
Я не знав цього про те, що розділ стає порожнім, і натомість потрібно його оживити ... Блін! Дякую!
dvkch

1
Отримав мій код для роботи з великою допомогою з цієї відповіді. Опублікувавши його нижче.
love2script12

2

У мене була та ж помилка.

Я використовував наступні рядки

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

зареєструвати перо в методі viewDidLoad, оскільки у мене був інший перо, яке також було пов'язане з тим самим класом. Отже, лінія

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

повертав нуль, якщо я не зареєстрував перо в viewDidLoad.

Моя проблема полягала в тому, що я забув встановити ідентифікатор в інспекторі атрибутів для мого файлу "CustomNib.xib" та "CustomNib ~ iphone.xib". (Або точніше, що я забув натиснути клавішу enter після введення ідентифікатора в інспекторі атрибутів у XCode, так що нове ім'я не вдалося зберегти.)

Сподіваюся, це допомагає.


2
Я НЕ думаю, що ваша відповідь має відношення до питання.
DawnSong

2

Якщо ви використовуєте NSFetchedResultsControllerподібний до мене і оновлюєте дані у фоновому потоці, не забувайте починати та закінчувати оновлення в делегаті:

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

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

2

У мене була та сама помилка, яка при спробі [tableView reloadData]роботи працювала нормально. Помилка насправді була в рядку

[TabView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationRight];

Коли я намагався перевірити значення indexPath, вони були неправильними, як потрібно.

Я виправив це, змінивши значення в indexPathsArray.

Сподіваюся, це допомагає.


1

Це може бути одним із UITableViewDataSourceметодів протоколу

Для

- tableView:numberOfRowsInSection:

він повинен повернути ціле число, рівне сумі або результату

-insertRowsAtIndexPaths:withRowAnimation:та / або -deleteRowsAtIndexPaths:withRowAnimation:

Для

- numberOfSectionsInTableView:

він повинен повернути ціле число, рівне сумі або результату

-insertRowsAtIndexPaths:withRowAnimation: та / або -deleteSections:withRowAnimation:


0

У мене була та сама проблема з базою даних. Якщо ви використовуєте багато FRC, вам просто потрібно перезавантажити подання таблиці всередині кожної умови в numberOfSectionsInTableView.


2
У мене також є ця проблема з основними даними. Чи можете ви, детальніше, описати свій рецепт?
Drux

0

У мене це трапилося зі мною, коли я використовував Swift та підтримку FRC для управління інформацією. Додавання простої перевірки до операції видалення для оцінки поточного indexPath.section дозволило мені уникнути сторонніх викликів. Здається, я розумію, чому виникає ця проблема ... В основному я завантажую повідомлення у верхній рядок, коли мій набір даних порожній. Це створює вимкнення для однієї проблеми, оскільки існує помилковий рядок.

Моє рішення

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

Просто переконайтеся, що ви викликаєте [yourTableView reloadData]; після зміни масиву значень.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.