UITableView insertRowsAtIndexPaths, бросающий __NSArrayM insertObject: atIndex: ошибка "объект не может быть nil"
Я пытаюсь динамически вставлять элемент в свой табличный вид. В моем приложении есть раздел чата, где он отображает старые (загруженные с сервера до инициализации контроллера представления) сообщения в разделе 0 и отображает только отправленные/полученные сообщения (где он изначально нул) в разделе 1. Когда загрузка загружается, все "старые" сообщения загружаются и отображаются, никаких проблем нет. Проблема начинается, когда я пытаюсь вставить строки. Вот что я делаю:
- Я сначала обновляю свой источник данных таблицы, добавляя дополнительный элемент:
[newMessages addObject:newMessage];
(newMessage - это экземпляр моего настраиваемого объекта сообщения, а newMessages - мой источник данных). Я проверяю, что у моего источника данных теперь есть 1 элемент (который был добавлен до 0).
-
Затем я вызываю следующий код:
[self.chatTableView beginUpdates];
[self.chatTableView insertRowsAtIndexPaths:@[[NSIndexPath
indexPathForRow:newMessages.count - 1 inSection:1]]
withRowAnimation:UITableViewRowAnimationBottom];
[self.chatTableView endUpdates];
Мое приложение разбивается на метод endUpdates
, давая мне эту ошибку: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Я сразу же проверил, есть ли newMessage
nil
или нет, он не nil
(и повторно проверил мой источник данных), поэтому источник данных не является проблемой. Я думал, что проблема indexPathForRow:newMessages.count - 1
может быть проблемой, и попробовал разные значения (count - 2, count, count + 1) на всякий случай, если я что-то упустил. В таких случаях я получаю еще одну ошибку: 'NSInternalInconsistencyException', reason: 'attempt to insert row 1 into section 1, but there are only 1 rows in section 1 after the update'
. Ошибка говорит обо всем, поэтому проблема не в том, чтобы с indexPathForRow:newMessages.count - 1
.
Я добавил точки останова в метод -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
, чтобы увидеть, когда он точно вызван и что он возвращает. Похоже, что метод вообще не вызывается, точка останова не попадает (он срабатывает, когда представление сначала загружается и загружает исходные данные правильно, и я не устанавливаю источник данных нигде, поэтому также связаны делегаты/источники данных правильно). Сразу же я проверил другие методы:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 2;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
if(section == 0){
return @"Eski mesajlar";
}else{
return @"Yeni mesajlar";
}
}
Эти методы возвращают правильные значения. Я поставил точку останова в -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
, чтобы увидеть, когда она вызвана. По-видимому, он вызван внутри метода [self.chatTableView endUpdates];
(как видно из стека вызовов потока/очереди), но затем [self.chatTableView endUpdates];
сразу же выдает ошибку, даже не введя метод -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
. Я видел примеры (и некоторые другие), такие как:
Я читал ответы там, но никто из них не помог мне. Что я делаю неправильно?
Ответы
Ответ 1
Есть ли у вас tableView:estimatedHeightForRowAtIndexPath:
? Я заметил аналогичную проблему в одном из моих собственных приложений, в котором используется NSFetchedResultsController
, где приложение вылетает с тем же сообщением об ошибке при вызове tableView:endUpdates
. Комментирование tableView:estimatedHeightForRowAtIndexPath:
исправил его для меня.
Ответ 2
Что касается удаления/комментирования tableView:estimatedHeightForRowAtIndexPath:
, это было не так, как я разрешил его, так как у меня не было этого метода для моего делегата.
Вместо этого я действительно установил tableView.estimatedSectionHeaderHeight = 10.;
в мой viewDidLoad
. Оказывается, просто комментируя эту строку, исключение больше не происходит, и тогда это работает так, как я ожидаю.
Это слишком плохо, потому что я не могу сказать, почему комментирование этого (или метод estimatedHeightForRowAtIndexPath:
) исправляет его.
Ответ 3
Недавно я разрешил эту проблему, не комментируя estimatedHeightForRowAtIndexPath:
. Конкретная проблема, которую я имел, заключалась в том, что в нашей таблице было много ячеек разных размеров, поэтому мы просто использовали средний размер в оценке. Исправление заключалось в том, чтобы лучше оценить размер вставленных ячеек.
Мое предположение состоит в том, что ошибка вызвана таблицей, пытающейся перейти к вставленной ячейке. По-видимому, ранее оцененное contentSize вызывает проблемы при прокрутке к вставленным ячейкам с высотой, которые были оценены слишком малыми.
Ответ 4
У меня была эта проблема и исправлена, не вставляя, если таблица пуста. Другими словами, если таблица не имеет строк, то не используйте insertRowAtIndexPaths
. Вместо этого добавьте объект в свой массив или какой-либо источник данных, а затем вызовите [myTableView reloadData]
Ответ 5
Я считаю, что ваша ошибка находится в методе tableView:numberOfRowsInSection:
. Метод insertRowsAtIndexPaths
вызывает этот метод перед вызовом tableView:cellForRowAtIndexPath
, и это не соответствует источнику данных, это может быть проблема.
Я вижу, что newMessages
- это локальная переменная, поэтому он, вероятно, не синхронизируется с массивом, возвращающимся из метода tableView:numberOfRowsInSection:
.
Чтобы устранить проблему, просто убедитесь, что tableView: numberOfRowsInSection возвращает правильный номер при выполнении обновлений.
Кроме того: даже если newMessages был равен нулю, метод count вернет 0 - Objective-C работает таким образом.