-1

I am trying to get the previously selected row and the currently selected row from the UITableview didSelectRowAt method.

The didSelectRowAt method only provides the row that was selected.

Is there a way to know which row was selected before didSelectRowAt was called?

Gene Z. Ragan
  • 2,643
  • 2
  • 31
  • 41
jo solution
  • 401
  • 5
  • 18
  • 1
    Use [`tableView(_:willSelectRowAt:) `](https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614943-tableview) – RajeshKumar R Oct 08 '19 at 14:25

2 Answers2

4

You just need to declare two properties to store the previously and currently selected rows, then update their values in tableView(_:didSelectRowAt:).

class TableViewController: UITableViewController {
    var lastSelectedRow: IndexPath?
    var currentlySelectedRow: IndexPath?

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        super.tableView(tableView, didSelectRowAt: indexPath)
        lastSelectedRow = currentlySelectedRow
        currentlySelectedRow = indexPath
    }
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • 1
    you can always ask for selectedRows with tableView.indexPathForSelectedRows.... ;) – Chris Oct 08 '19 at 14:54
  • @Chris yes, but then you won't be notified when it changes :) And there's no reason to access it using the property when the delegate method provides access already – Dávid Pásztor Oct 08 '19 at 15:17
  • 1
    Saving state about previously selected rows is risky. It isn't a good idea to be caching IndexPaths as the contents of a table view are dynamic. What if the IndexPath becomes invalid when the total number of items in the table view change and the cached path becomes out of bounds? This is just one of the potential problems with this type a state caching. – Gene Z. Ragan Oct 08 '19 at 20:00
3

The UITableViewDelegate protocol has several methods to help you manage the state of your table view.

Do not cache IndexPaths as they can easily become stale and invalid. Your code will eventually encounter an invalid IndexPath and the application will crash when the invalid object is used.

Instead, use the methods that inform you what row is going to be selected. Within the willSelectRowAt you can then get the current selection state of the table view by calling indexPathForSelectedRow and perform the actions you want with the selection information.

class TableViewController: UITableViewController {

     override func tableView(UITableView, willSelectRowAt: IndexPath) -> IndexPath? {
          let selectedIndexPath = self.tableView.indexPathForSelectedRow()
          // Do something with the selected path
     }
}
Gene Z. Ragan
  • 2,643
  • 2
  • 31
  • 41
  • "You code will eventually encounter an invalid IndexPath and the application will crash when the invalid object is used." That's not necessarily true. As long as you make sure you validate the cached indexpaths before using them for indexing the data source array, you're absolutely safe from crashes. Also, without knowing what exactly OP needs this caching for, it's hard to judge whether it is safe or not. – Dávid Pásztor Oct 08 '19 at 20:21
  • This statement can be made about the caching of any sort of state. Saying that you are free to cache anything you want as long as you perform exhaustive checks to ensure the validity of the cached state pushes the limits of credulity in this case. Apple has provided explicit calls to deal with selection state for this very reason. If you wish to support your answer, please also add the code to validate the cached objects before usage. After you do that, compare your code to the use the stateless behavior enabled by the protocol methods. – Gene Z. Ragan Oct 08 '19 at 20:52