UITableView
iOS Development
Swift Programming
Mobile App Development
iOS TableView Index

Get Selected index of UITableView

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In UITableView, selection is represented by an IndexPath, not just a row number. That matters because a table view can have multiple sections, so the selected item is really a combination of section and row.

The right API depends on when you need the answer. If you want the selected row at the moment the user taps it, use the delegate callback. If you need the current selection later, ask the table view for its selected index path.

Understand the Selection APIs

The two most common approaches are:

  • 'tableView(_:didSelectRowAt:) when you want to react immediately to a tap'
  • 'tableView.indexPathForSelectedRow when you want to inspect the current selection later'

Both APIs return an IndexPath, which contains section and row. If your table only has one section, indexPath.row is usually the part you care about. If the table can select multiple rows, use indexPathsForSelectedRows instead.

Capture the Selected Row in the Delegate

The delegate callback is the simplest place to read the selected index because UIKit passes it to you directly:

swift
1import UIKit
2
3final class FruitViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
4    private let tableView = UITableView(frame: .zero, style: .plain)
5    private let fruits = ["Apple", "Banana", "Cherry"]
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        tableView.frame = view.bounds
10        tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
11        tableView.dataSource = self
12        tableView.delegate = self
13        view.addSubview(tableView)
14    }
15
16    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
17        fruits.count
18    }
19
20    func tableView(
21        _ tableView: UITableView,
22        cellForRowAt indexPath: IndexPath
23    ) -> UITableViewCell {
24        let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
25        cell.textLabel?.text = fruits[indexPath.row]
26        return cell
27    }
28
29    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
30        let selectedFruit = fruits[indexPath.row]
31        print("Selected section: \(indexPath.section)")
32        print("Selected row: \(indexPath.row)")
33        print("Selected value: \(selectedFruit)")
34    }
35}

This is the best place to respond to user intent. You already know which cell was tapped, so there is no need to query the table again.

Read the Current Selection Later

Sometimes the selection matters outside the tap callback. For example, a toolbar button might need to act on the selected row. In that case, ask the table view for its current selection:

swift
1@objc private func showCurrentSelection() {
2    guard let indexPath = tableView.indexPathForSelectedRow else {
3        print("No row is selected")
4        return
5    }
6
7    print("Current row: \(indexPath.row)")
8}

This works only when the table actually maintains a selection. If you deselect rows immediately after tapping, indexPathForSelectedRow may be nil by the time you check it.

If the table allows multiple selection, use the plural API:

swift
1tableView.allowsMultipleSelection = true
2
3if let selectedRows = tableView.indexPathsForSelectedRows {
4    for indexPath in selectedRows {
5        print("Selected row: \(indexPath.row)")
6    }
7}

Section and Row Both Matter

Developers often say "selected index" when they really mean indexPath.row. That is fine in a one-section table, but it breaks down as soon as you introduce sections. A row value of 2 could mean the third item in section 0 or the third item in section 3.

When you use the selected value to read from a data source, mirror the same structure as the table. If the table has sections, your backing array or model should be section-aware too.

Common Pitfalls

One common mistake is trying to read the selection before the user has selected anything. In that case indexPathForSelectedRow returns nil, so always unwrap it safely.

Another problem is confusing highlight state with selection state. A row can appear highlighted briefly during touches even when it is not the persistent selected row.

Developers also sometimes store only the row number and ignore the section. That creates subtle bugs as soon as the table becomes more complex.

Finally, if you call tableView.deselectRow(at:animated:) in didSelectRowAt, the table will not continue to report that row as selected later. That is often the right UI behavior, but it changes which API is appropriate.

Summary

  • Use didSelectRowAt when you want the selected index at the moment the user taps a row.
  • Use indexPathForSelectedRow when you need to inspect the current selection later.
  • Read both section and row, not just the row number, when the table has multiple sections.
  • Expect nil when no row is selected or when you deselect the row immediately after handling the tap.

Course illustration
Course illustration

All Rights Reserved.