Unable to insert row in TableView, failing with NSInternalInconsistencyException

Hi,


I am unable to insert a new row into my table view, I get the following error while adding a new row:


reason: 'attempt to insert row 3 into section 0, but there are only 3 rows in section 0 after the update'


The following is my code:


source.append(data)
let indexPath = IndexPath(row: (source.count), section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)


The Above code deosn't work but it works if change the code to the following


let indexPath = IndexPath(row: (source.count), section: 0)
source.append(data)
tableView.insertRows(at: [indexPath], with: .automatic)


So I really confused as the why the code works if generate a new IndexPath before appending the new data to the table's datasource.


The only thing i can come up with is that Index Path is initialized to a value at which there is no element in the array.


Also I debugged which functions are called when insertRows is executed, first the numberOfRows functions are calleld which in both cases return 3 and then the cellForRowAt if the code doesn't fail


Can anybody point me in the right direction as what I am missing in my knowleadge of TableView's

Answered by QuinceyMorris in 285120022

I think it's worth pointing out that the problem here is nothing to do with table views, but is a straightforward "off by 1" error.


The easiest way to "see" the error is to take the edge case where the table is empty. An inserted row must then be row 0, not row 1, so any calculation that produces an index path with row 1 (such as the OP's first code fragment) is simply off by 1.


This is unrelated to the table-view-specific problem where the data model and the table view become inconsistent during an update cycle.

Your example illustrates the behaviour quite well. The insertRows method takes an array of index paths representing the places where the new rows *will be* inserted in the *existing* table. So yes, if you want to add rows at the end, you have to specify the index of the *current* last element +1, not what it will be after the updates are finished.


For more information: https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/TableView_iPhone/ManageInsertDeleteRow/ManageInsertDeleteRow.html#//apple_ref/doc/uid/TP40007451-CH10-SW9

Accepted Answer

I think it's worth pointing out that the problem here is nothing to do with table views, but is a straightforward "off by 1" error.


The easiest way to "see" the error is to take the edge case where the table is empty. An inserted row must then be row 0, not row 1, so any calculation that produces an index path with row 1 (such as the OP's first code fragment) is simply off by 1.


This is unrelated to the table-view-specific problem where the data model and the table view become inconsistent during an update cycle.

Thanks QuinceyMorris pointing out the mistake and providing an example case

It's really an "off by N" error, where N is the number of table rows you're inserting. The index paths you need specify are the indices *before* any updates are performed.


In this simple case N = 1 but the problem is a misunderstanding of when you need to calculate the indices, in my opinion.

Unable to insert row in TableView, failing with NSInternalInconsistencyException
 
 
Q