Reputation: 2708
I am trying to reorder the chats in a tableView. The most recent updated chat should be insert at IndexPath(row: 0, section: 1)
.
My understanding is that in order to delete a row, it must be visible.
If the row is not visible, when Data Source is updated, I just have to tableView.insertRows(at: [newIndex], with: .fade)
.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (17) must be equal to the number of rows contained in that section before the update (17), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
//chats of the currentUser
var currentUserChats = [Chat]() {
didSet(newValue){
attachChildChangedObserverOn(chat: newValue)
}
}
var observersArray = [String: UInt]() // chatUID: handle
//attach childChange listener on each chat downloaded
func attachChildChangedObserverOn(chat: Chat) {
var handle: UInt = 0
let ref = DDatabaseRReference.chats.reference().child(chat.chatUID).child("users").child(currentUser.userUID)
handle = ref.observe(.childChanged, with: {[weak self] (snapshot) in
self?.observersArray[chat.chatUID] = handle
guard snapshot.exists() else {return}
let chatChanged = chat
var lastMessage = ""
var unreadMessagesCount = 0
var lastUpdate = 0.0
switch snapshot.key {
case "lastMessage" :
lastMessage = snapshot.value as! String
chatChanged.lastMessage = lastMessage
case "unreadMessagesCount":
unreadMessagesCount = snapshot.value as! Int
if let index = chatChanged.users.index(of: (self?.currentUser)!) {
let userChanged = chatChanged.users[index]
userChanged.unreadMessagesCount = unreadMessagesCount
chatChanged.users.remove(at: index)
chatChanged.users.insert(userChanged, at: index)
}
case "lastUpdate":
lastUpdate = snapshot.value as! Double
chatChanged.lastUpdate = lastUpdate
default: return
}
let newIndex = IndexPath(row: 0, section: 1)
// get indexOf chatChanged
guard let index = self?.currentUserChats.index(of: chatChanged) else {return}
let indexPathOfOldChat = IndexPath(row: index, section: 1)
// - update Data Source
// - reloadRow
if indexPathOfOldChat.row == 0 {
self?.currentUserChats.remove(at: 0)
self?.currentUserChats.insert(chatChanged, at: 0)
self?.tableView.reloadRows(at: [newIndex], with: .fade)
return
}
//get visible indexes of cells in TableView
let visibleIndexes = self?.tableView.indexPathsForVisibleRows
//check if the index of chat to be updated is visible
if let indexes = visibleIndexes,
indexes.contains(indexPathOfOldChat) {
//index is visible
// update Data Source, delete row & insert row
self?.tableView.beginUpdates()
self?.currentUserChats.remove(at: indexPathOfOldChat.row)
self?.tableView.deleteRows(at: [indexPathOfOldChat], with: .fade)
self?.currentUserChats.insert(chatChanged, at: 0)
self?.tableView.insertRows(at: [newIndex], with: .fade)
self?.tableView.endUpdates()
return
}
//if index is not visible:
// - update Data Source
// - insert the row
self?.currentUserChats.remove(at: index)
self?.currentUserChats.insert(chatChanged, at: 0)
self?.tableView.beginUpdates()
self?.tableView.insertRows(at: [newIndex], with: .fade)
self?.tableView.endUpdates()
return
})
}
Upvotes: 3
Views: 6997
Reputation: 2708
It turns out that rows that are not visible can be deleted.
Initially, I had thought that I would get an error if I tried to delete a row that was not visible because that cell for that row would no longer be in the view.
//if index is not visible:
// - update Data Source
// - DELETE the previous row
// - insert the new row
self?.currentUserChats.remove(at: indexRow)
self?.currentUserChats.insert(chatChanged, at: 0)
self?.tableView.beginUpdates()
self?.tableView.deleteRows(at: [indexPathOfOldChat], with: .none)
self?.tableView.insertRows(at: [newIndex], with: .fade)
self?.tableView.endUpdates()
return
Upvotes: 1