bibscy
bibscy

Reputation: 2708

'Invalid update: invalid number of rows in section 1

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

Answers (1)

bibscy
bibscy

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

Related Questions