iOS development
UITableView
Swift programming
indexPath.row
mobile app development

How to get the indexpath.row when an element is activated?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Getting indexPath.row is easy when the table view itself tells you which row was selected. It becomes more interesting when the activated element is a button, switch, or gesture target inside the cell. The correct solution depends on where the event originates, but the common theme is the same: translate the event back to the cell or pass the row context explicitly.

Use didSelectRowAt for Cell Selection

If the user taps the row itself, UITableViewDelegate already gives you the index path.

swift
1import UIKit
2
3final class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
4    let tableView = UITableView()
5    let items = ["One", "Two", "Three"]
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        tableView.frame = view.bounds
10        tableView.dataSource = self
11        tableView.delegate = self
12        view.addSubview(tableView)
13    }
14
15    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
16        items.count
17    }
18
19    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
20        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
21        cell.textLabel?.text = items[indexPath.row]
22        return cell
23    }
24
25    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
26        print("Selected row:", indexPath.row)
27    }
28}

When this callback exists, do not invent extra lookup logic. The table view is already telling you exactly which row fired the action.

For Controls Inside a Cell, Convert the Sender Position

If the activated element is a button inside the cell, one direct approach is to convert the sender's coordinate into the table view and ask for the index path at that point.

swift
1@objc func buttonTapped(_ sender: UIButton) {
2    let point = sender.convert(CGPoint.zero, to: tableView)
3    if let indexPath = tableView.indexPathForRow(at: point) {
4        print("Button tapped in row:", indexPath.row)
5    }
6}

This works because the table view can map a point in its coordinate system back to the row located there.

Passing Context from the Cell Is Often Cleaner

The coordinate-conversion trick works, but many codebases are easier to maintain when the cell reports its action through a closure or delegate.

swift
1final class ItemCell: UITableViewCell {
2    var onTap: (() -> Void)?
3    let actionButton = UIButton(type: .system)
4
5    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
6        super.init(style: style, reuseIdentifier: reuseIdentifier)
7        actionButton.setTitle("Tap", for: .normal)
8        actionButton.addTarget(self, action: #selector(handleTap), for: .touchUpInside)
9        contentView.addSubview(actionButton)
10    }
11
12    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
13
14    @objc private func handleTap() {
15        onTap?()
16    }
17}

Then configure the closure in cellForRowAt using the current indexPath.row. This makes the ownership clearer and avoids view-hierarchy guessing.

Be Careful with Reuse

Table view cells are reused. If you store row numbers directly on a cell or button and forget to update them during reuse, actions can point at stale data.

That is why closure configuration or index-path lookup at event time is usually safer than trying to keep a permanent row value attached to the view itself.

It is also why you should prefer stable model identifiers when the action targets the underlying data rather than the current visible position. Rows can move after inserts, deletes, and sorting.

Use the Right Source of Truth

indexPath.row tells you the position in the current table section. It is not a durable business identifier. If the user taps an item and you need to update your model, prefer using items[indexPath.row] or the model's ID instead of treating the row number as meaningful beyond the current UI state.

That small distinction prevents a lot of bugs in editable tables.

Common Pitfalls

  • Recreating row lookup logic when didSelectRowAt already provides the index path.
  • Storing row numbers on reusable views and then forgetting to refresh them.
  • Treating indexPath.row as a permanent identifier instead of a UI position.
  • Walking superviews manually to find the cell when a cleaner closure or delegate approach would work.
  • Ignoring section information when the table has more than one section.

Summary

  • Use didSelectRowAt when the row itself was tapped.
  • For controls inside the cell, either convert the sender's point or pass context from the cell.
  • Be careful with cell reuse and moving rows.
  • Use the model object, not just the row number, for real business actions.
  • Treat indexPath.row as UI location data, not as a durable identifier.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.