19

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?

braX
  • 11,506
  • 5
  • 20
  • 33
Mischa
  • 15,816
  • 8
  • 59
  • 117

5 Answers5

27

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];
JeroValli
  • 569
  • 4
  • 10
11

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];
}
Mischa
  • 15,816
  • 8
  • 59
  • 117
  • but this will call the DidselectRowAtIndexPath again for each previously selected cells. And will trigger the actions I have coded for when the user selects a cell. – omarojo May 25 '17 at 05:32
3

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.
vadian
  • 274,689
  • 30
  • 353
  • 361
0

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)
        }
Justin Domnitz
  • 3,217
  • 27
  • 34
0

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)
    })
}
muhasturk
  • 2,534
  • 20
  • 16
  • 1
    That's **a** way, but not ***the** correct* way. Keeping the *selected* state for each cell in the data model is much more efficient. – vadian Dec 06 '18 at 09:17
  • 1
    Every UITableViewCell subclass already have "isSelected" property for each cell. Think that you need to change selected state of desired cell without reloading table view. You can not archive this purpose by keeping selected state in data model. So in my opinion, using predefined isSelected property is more correct. – muhasturk Dec 06 '18 at 11:59
  • Yes you can. The `isSelected` property of the **view** is supposed to mirror the state of the `isSelected` property of the **model** and vice versa. Manipulating the view directly is pretty bad habit and inefficient. – vadian Dec 06 '18 at 12:03
  • If you save selected state in data model, you have to reload whole or particular (row / section) table to change selected view of cell. You said that "Yes we can". Can you send me a snippet of code that changes selected view of cell without reloading? – muhasturk Dec 06 '18 at 12:21
  • Of course you have to reload this (one) particular row. But this is **much** more efficient than getting all selected cells, create a new variable to keep the data, reload the **entire** table view and reassign the selected state of each cell in a loop. – vadian Dec 06 '18 at 12:24