How to create NSIndexPath for TableView
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
NSIndexPath is one of the most commonly used classes in iOS development when working with UITableView and UICollectionView. It represents a path to a specific item within a nested collection, and in the context of table views, it identifies a cell by its section and row. Understanding how to create and use NSIndexPath correctly is essential for tasks like programmatic scrolling, cell selection, inserting or deleting rows, and responding to user interactions.
What is NSIndexPath?
Think of a table view as a two-level structure. The first level is the section (a group of related rows), and the second level is the row within that section. NSIndexPath encodes both of these values into a single object. For example, an index path with section 0 and row 2 points to the third row (zero-indexed) in the first section.
UIKit extends NSIndexPath with two convenience properties -- section and row -- that you will use constantly when working with table views.
Creating NSIndexPath in Swift
The most common way to create an NSIndexPath for a table view is through the IndexPath(row:section:) initializer. In Swift, you typically work with the IndexPath struct (which is bridged to NSIndexPath):
You can use this index path to perform operations on the table view, such as scrolling to a specific cell:
Or selecting a row programmatically:
Creating NSIndexPath in Objective-C
In Objective-C, you use the NSIndexPath class method indexPathForRow:inSection::
Using NSIndexPath in UITableViewDataSource and Delegate
Index paths appear throughout the table view data source and delegate methods. Here is a typical implementation that demonstrates how you receive and use index paths:
Inserting and Deleting Rows with NSIndexPath
When you modify the data source and need the table view to reflect changes, you pass arrays of index paths to the insertion and deletion methods:
Wrap multiple insertions and deletions inside tableView.performBatchUpdates (or beginUpdates/endUpdates on older iOS versions) to animate them together smoothly.
Common Pitfalls
- Off-by-one errors with zero-based indexing: Both
rowandsectionare zero-indexed. If your table has 5 rows, valid row values are 0 through 4. Passing row 5 will cause an out-of-range crash at runtime. - Mismatched data source and index paths: When inserting or deleting rows, you must update your data source array before calling
insertRows(at:)ordeleteRows(at:). If the data source count does not match what the table view expects after the update, you will get anNSInternalInconsistencyException. - Confusing row and item for collection views:
UICollectionViewusesIndexPath(item:section:)with anitemproperty instead ofrow. UsingindexPath.rowon a collection view works due to bridging but can cause confusion when reading code. Useitemfor collection views androwfor table views. - Storing index paths across reloads: Index paths become invalid after calling
reloadData()because rows may have shifted. Never cache an index path and reuse it after a data reload. Instead, store the underlying data identifier and look up the current index path when needed. - Forgetting to handle multiple sections: Many beginners hardcode section 0 everywhere. If your table later gains multiple sections, all those hardcoded values will point to the wrong data. Always use
indexPath.sectionto look up the correct data array, even if you currently have only one section.
Summary
NSIndexPath(bridged asIndexPathin Swift) identifies a cell in a table view by its section and row, both zero-indexed.- In Swift, create index paths with
IndexPath(row:section:). In Objective-C, use[NSIndexPath indexPathForRow:inSection:]. - Index paths are used throughout
UITableViewDataSourceandUITableViewDelegatemethods for cell configuration, selection, and modification. - Always keep your data source in sync with the table view when inserting or deleting rows using index paths.
- Use
indexPath.rowfor table views andindexPath.itemfor collection views to keep your code clear and intention-revealing.

