Reputation: 1346
[UPDATE]
I've found the problem. I've created a custom UITableViewCell, and am not using the standard methods to trigger deletion. My custom UITableViewCell has a custom indexPath property that I populate when creating the cell. That's why it doesn't get updated without a call to reload data.
As a workaround, to minimize code rewriting, I'm using the solution marked as the answer.
[/UPDATE]
I've seen other questions similar to this, but not quite the same...
I have a UITableView that gets it's rows (cells) from objects in a NSArray. The rows are mapped to the NSArray using the indexPath.row. This means that the object at index 0 in the NSArray corresponds to the cell with indexPath.row 0.
Whenever I delete a row, I remove the object from the NSArray (as seen in many examples, including Apple's documentation).
The problem is, whenever a row is removed, the indexPath's aren't updated. For example:
I have a table view with 3 rows. This means I have indexPath.row 0, 1 and 2. Also, the corresponding NSArray objects a index 0, 1 and 2.
When I delete row 1 from the UITableView and remove the corresponding object in the NSArray, what remains is indexPath.row 1 and 2, but the the indexes for the NSArray are 0 and 1.
If I try to delete what is now the second row from the UITableView, I run into a problem because it's indexPath.row is 2, but the corresponding object in the NSArray has index 1.
To put it another way, the indexPath.row and object indexes are no longer "in sync".
People have suggested using UITableView's reloadData method... This, in fact, does "reset" the indexPaths, but interrupts the UITableView row animation.
How can I do a row delete, update the indexPaths and still maintain the UITableView's animations?!
Upvotes: 4
Views: 9833
Reputation: 830
I had a similar issue where I was assigning gesture recognizers to a cell and using the indexPath
in the gesture recognizer to interact with the data source.
Instead of using the indexPath
provided by tableview:cellForRowAtIndexPath:
when constructing the gesture recognizer, I instead get the indexPath
provided by cellForRowAtIndexPath:
method on the tableView. This approach provided the updated indexPath for
a cell even if cells were added or deleted.
Upvotes: 0
Reputation: 757
Please, note my answer in this another thread.
UITableView delete and reload cells
I had some problems related to it. Using fixed index probably you will face a lot of headache. I've solved this adding to the UITableViewCell a reference to a Item from my datasource, not a NSIndexPath. So, there is no need to use indexPath saved into your cell.
Also, there is some information on Apple's Website saying we mustn't use the method reloadData
inside insert or delete methods.
all this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible. It adjusts offsets if the table shrinks as a result of the reload. The table view's delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows, especially within an animation block implemented with calls to beginUpdates and endUpdates
Upvotes: 0
Reputation: 1478
Have a look how NSFetchedResultsControllerDelegate normally handles it: http://developer.apple.com/library/ios/#documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html
Basically all you need to do to remove a cell from the tableview is call [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]
If you have a number changes to make wrap them with [tableView beginUpdates]
and [tableView endUpdates]
to trigger all the animations at once.
If this still causes an out of sync issue, just use the old trick of deleting the last indexPath first and work your way up. That way all the intermediate indexPaths stay valid.
Upvotes: 2
Reputation: 1605
Not tested, but a couple things I can think of are either delay the reload until the animations complete. Or just reload those rows rather than the whole table using:
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
Delay:
[tableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.5];
Upvotes: 4