У меня есть UITableView, довольно стандартный, с довольно динамическим источником данных (сообщения).
Для добавления сообщений в UITableView я использую insertRows
.
func insertRowsInTableAtIndexPath(ip: IndexPath, right: Bool) {
print("INSERT ROW visible cells: \(tableView.visibleCells.count)\n dispatcher messages \(dispatcher.messages.count)\n numberOfRows \(tableView.numberOfRows(inSection: 0))\n numberOfSections \(tableView.numberOfSections)\n ip: \(ip.row) \(ip.section)")
if tableView != nil {
if right == true {
self.tableView.insertRows(at: [ip], with: UITableView.RowAnimation.right)
} else {
self.tableView.insertRows(at: [ip], with: UITableView.RowAnimation.left)
}
}
print("AFTER INSERT ROW visible cells: \(tableView.visibleCells.count)\n dispatcher messages \(dispatcher.messages.count)\n numberOfRows \(tableView.numberOfRows(inSection: 0))\n numberOfSections \(tableView.numberOfSections)\n ip: \(ip.row) \(ip.section)")
}
Это выглядит довольностандарт, потому что это так.Проблема в том, что в некоторых редких случаях (я могу воспроизвести их, но было бы довольно сложно описать их здесь), я получаю знаменитое NSInternalInconsistencyException
: Неверное обновление: недопустимое количество строк в разделе 0.количество строк, содержащихся в существующем разделе после обновления (2), должно быть равно количеству строк, содержащихся в этом разделе до обновления (0) и т. д.
В этих случаях первыйсообщение успешно добавлено в dataSource
, и похоже, что это сообщение также вставляется в виде строки, но оно не отображается на экране , и следующее сообщение нарушает мою UITableView
потому что это недействительное обновление (и оно есть).
Я знаю, что это происходит из-за всех этих команд печати до и после вставки ячейки.В плохом случае эти цифры выглядят так:
Перед вставкой первого сообщения:
visible cells: 0
number of messages in dataSource: 1
numberOfRows: 0
numberOfSections: 1
ip: 0 0 (indexPath.row, indexPath.section)
После вставки первого сообщения:
visible cells: 1
number of messages in dataSource: 1
numberOfRows: 1
numberOfSections: 1
ip: 0 0 (indexPath.row, indexPath.section)
На данный момент я могуя не вижу эту ячейку (которая была успешно вставлена, если я могу поверить UITableView.visibleCells.count
)
Но если я пытаюсь вставить следующее сообщение, я получаю исключение.Более того: UITableView.visibleCells.count
внезапно равно 0, а numberOfRows
также равно 0, хотя я не удалил предыдущую строку и не удалил это сообщение из dataSource
.
visible cells: 0
dispatcher messages 2
numberOfRows 0
numberOfSections 1
ip: 0 0
Итак, яЕсть три вопроса:
Возможно ли для UITableView не вставлять строку с insertRows
, и как я могу предотвратить это поведение.Почему первый ряд не отображается на первом месте?
Почему этот первый ряд исчезает из numberOfRows
и visibleCells
через некоторое время?
Что я здесь не так делаю?
Я понимаю, что такого количества кода недостаточно для решения этой проблемы с нуля, но этот UITableView
довольно стандартный, иЛогика источника данных не настолько стандартна и относительно сложна, поэтому я надеюсь только на людей, которые уже испытали нечто подобное.
обновление (методы источника данных) :
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dispatcher.messages.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
обновление 2 (наиболее значимая часть кода):
//this should work when user is changing from one 'chat' to another
//so, first of all, I'm removing all the messages from the dataSource
dispatcher.messages.removeAll()
//also, I'm stopping the timer
if timer != nil {
timer.invalidate()
timer = nil
}
//also, I'm reloading the table with no messages
if tableView != nil {
tableView.reloadData()
}
//after that I'm starting the timer again, and trying to add new messages to the UITableView. The first message is going through (although it is not shown in the UITableView as it should be), the second message is throwing an error because the first row doesn't exist at this point).
let newMessage = dispatcher.giveMeNewMessage()
if newMessage != nil {
dispatcher.messages.insert(newMessage!, at: 0)
let ip = IndexPath(row: 0, section: 0)
insertRowsInTableAtIndexPath(ip: ip, right: false)
self.scrollToRow(ip: ip) //standard scrollToRow
}