我有一个标准的UITableView,它具有非常动态的数据源(消息)。
我正在使用insertRows
将消息添加到UITableView。
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
是非常标准的,并且dataSource逻辑不是那么标准且相对复杂,所以我唯一的希望是已经经历过类似的事情。
更新(数据源方法):
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
}