UITableView selection not sticking when reloading cells

I have some UITableView code that was setting a selection, and then later making some other changes to the cell using reloadRowsAtIndexPaths:withRowAnimation: and I was having trouble figuring out why my selection wasn’t sticking. I’d select an object, but it wouldn’t show as selected.

Turns out reloadRowsAtIndexPaths:withRowAnimation: will deselect whatever rows you reload. Check this out:

[cc lang=”objc”]
// Create an NSIndexPath that indicates the 3rd row
NSIndexPath *path = [NSIndexPath indexPathForRow:3 inSection:0];

// Select it
[self.tableView selectRowAtIndexPath:path
animated:NO
scrollPosition:UITableViewScrollPositionNone];

// Is it still selected?
path = self.tableView.indexPathForSelectedRow;

// Yes, this will print the values you’d expect for that row being selected
NSLog(@”Path: %@”, path);

// Reload that row
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationNone];

// Now is it still selected?
path = self.tableView.indexPathForSelectedRow;

// Negatory, path is null.
NSLog(@”Path: %@”, path);
[/cc]

It’s not obvious from the documentation that this operation affects the selection, and it took me a while to figure out why my selection was being dropped. The fix is simple enough: Preserve the selection yourself around the reload call.

[cc lang=”objc”]
// Save the current selection
NSIndexPath *savedSelection = self.tableView.indexPathForSelectedRow;

// Reload
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationNone];

// And restore the selection
[self.tableView selectRowAtIndexPath:savedSelection
animated:NO
scrollPosition:UITableViewScrollPositionNone];
[/cc]