Misha Timofeev Misha Timofeev - 21 days ago 6
iOS Question

Can't insert rows in table view

I read all of the related posts about this problem, but I am still having an error:

'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (13) must be equal to the number of rows contained in that section before the update (13), plus or minus the number of rows inserted or deleted from that section (11 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'


Here is the code:

func appendItems(entities: [Entity]) {
if entities.count > 0 {
let entitesFirstPos = items.count
self.items.append(contentsOf: entities)
var indexPaths: [IndexPath] = []
for i in entitesFirstPos..<items.count {
indexPaths.append(IndexPath(row: i, section: 0))
}

self.tableView.beginUpdates()
self.tableView.insertRows(at: indexPaths, with: .none)
self.tableView.endUpdates()
}
}

Answer

Looks like appendItems() is a function in a subclass of UITableViewController. If that's the case, try the following. It's impossible to give an exact answer without knowing what your tableView(UITableView, numberOfRowsInSection: Int) and tableView(UITableView, cellForRowAt: IndexPath) look like. So this is based on the assumption that self.items is simply an array that contains the data for all the cells in section 0.

First try to make this change:

//self.tableView.beginUpdates()
//self.tableView.insertRows(at: indexPaths, with: .none)
//self.tableView.endUpdates()
self.tableView.reloadData()

Making that change would update your table view without performing the row insert animation as a batch for all the new rows. If that works your issue is just within the appendItems() function. In that case try to make these changes:

func appendItems(entities: [Entity]) {
    if entities.count > 0 {
        self.tableView.beginUpdates() // <--- Insert this here
        let entitesFirstPos = items.count
        self.items.append(contentsOf: entities)
        var indexPaths: [IndexPath] = []
        for i in entitesFirstPos..<items.count {
            indexPaths.append(IndexPath(row: i, section: 0))
        }

        //The following line is now at the top of the block.
        //self.tableView.beginUpdates() 
        self.tableView.insertRows(at: indexPaths, with: .none)
        self.tableView.endUpdates()
    }
}

Making this change will make sure that if the number of rows in a section is queried by the UITableView before the call to the beginUpdates() function or even by that function itself the correct number of rows will be returned. In your current setup, assuming that self.items represents the table view data, the updated number of rows will be visible already before beginUpdates() is called. If that doesn't work, some more of your code is needed to pinpoint the issue.

Comments