Question

I have a table view with selectable rows. When I reload the table view some new rows might be added (or removed) and some labels in the table view's cells might change. That's what I want to achieve by calling [tableView reloadData].

Unfortunately that method also clears the table view's whole state - including the selection. But I need to keep the selection.

So how can I reload all the data in a table view while still keeping the selected rows selected?

Was it helpful?

Solution

You can store the index path of the selected row with:

rowToSelect = [yourTableView indexPathForSelectedRow];

Before reload the data. And after reload use:

[yourTableView selectRowAtIndexPath:rowToSelect animated:YES scrollPosition:UITableViewScrollPositionNone];

OTHER TIPS

JeroVallis solution works for single selection table views. Based on his idea this is how I made it work with multiple selection:

NSArray *selectedIndexPaths = [self.tableView indexPathsForSelectedRows];
[tableView reloadData];
for (int i = 0; i < [selectedIndexPaths count]; i++) {
    [tableView selectRowAtIndexPath:selectedIndexPaths[i] animated:NO scrollPosition:UITableViewScrollPositionNone];
}

The most efficient way is to keep the selected state in the data model

  • Add a boolean property isSelected in the struct or class which represents the data source.
  • In cellForRowAt set the selected state of the cell according to the property.
  • In didSelectRow toggle isSelected in the data source item and reload only the particular row at the given index path.

An alternative that has some advantages is to only reload the rows that have not been selected. Swift code below.

        if var visibleRows = tableView.indexPathsForVisibleRows,
            let indexPathIndex = visibleRows.index(of: indexPath) {
            visibleRows.remove(at: indexPathIndex)
            tableView.reloadRows(at: visibleRows, with: .none)
        }

Swift 4.2 Tested

The correct way to update selected rows after reload table view is:

// Saves selected rows
let selectredRows = tableView.indexPathsForSelectedRows

tableView.reloadData()

// Select row after table view finished reload data on the main thread
DispatchQueue.main.async {
    selectredRows?.forEach({ (selectedRow) in
        tableView.selectRow(at: selectedRow, animated: false, scrollPosition: .none)
    })
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top