Row Selection
Respond to user taps and manage selection state in your data table.
When a user taps a cell in your data table, you'll want to respond — maybe navigate to a detail screen, show an action sheet, or update some state. SwiftDataTables uses the delegate pattern to notify you of these events.
Setting Up the Delegate
The delegate pattern requires two steps: conform to the protocol, and assign yourself as the delegate.
class EmployeeListViewController: UIViewController, SwiftDataTableDelegate {
var dataTable: SwiftDataTable<Employee>!
var employees: [Employee] = []
override func viewDidLoad() {
super.viewDidLoad()
let columns: [DataTableColumn<Employee>] = [
.init("Name", \.name),
.init("Department", \.department)
]
dataTable = SwiftDataTable(columns: columns)
dataTable.delegate = self // Tell the table to notify us of events
dataTable.setData(employees)
view.addSubview(dataTable)
}
}All delegate methods are optional. Only implement the ones you need — the table works fine without a delegate.
Responding to Taps
Implement didSelectItem to respond when a user taps any cell. You receive an IndexPath that tells you exactly which cell was tapped.
Understanding the IndexPath
SwiftDataTables uses IndexPath differently than UITableView. Here's the mapping:
| Property | What It Means | Example |
|---|---|---|
indexPath.section | The row (0-indexed) | Row 0 = first data row |
indexPath.item | The column (0-indexed) | Column 0 = first column |
Note that section is the row, not the column. This matches UICollectionView semantics where each row is a section.
Basic Selection Handler
func didSelectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath) {
let rowIndex = indexPath.section
let columnIndex = indexPath.item
// Get the model for this row
let employee = employees[rowIndex]
// Get the column name if needed
let columnName = columns[columnIndex].header
print("Tapped \(employee.name)'s \(columnName) cell")
}Common Patterns
Navigate to Detail View
The most common pattern: tap a row to see more details.
func didSelectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath) {
let employee = employees[indexPath.section]
let detailVC = EmployeeDetailViewController(employee: employee)
navigationController?.pushViewController(detailVC, animated: true)
}Show Action Sheet
Let users choose what to do with the selected item.
func didSelectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath) {
let employee = employees[indexPath.section]
let sheet = UIAlertController(
title: employee.name,
message: employee.department,
preferredStyle: .actionSheet
)
sheet.addAction(UIAlertAction(title: "View Profile", style: .default) { _ in
self.showProfile(for: employee)
})
sheet.addAction(UIAlertAction(title: "Send Email", style: .default) { _ in
self.composeEmail(to: employee)
})
sheet.addAction(UIAlertAction(title: "Delete", style: .destructive) { _ in
self.confirmDelete(employee)
})
sheet.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(sheet, animated: true)
}Column-Specific Actions
Sometimes the action depends on which column was tapped.
func didSelectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath) {
let employee = employees[indexPath.section]
let column = indexPath.item
switch column {
case 0: // Name column
showProfile(for: employee)
case 1: // Email column
composeEmail(to: employee)
case 2: // Phone column
callPhone(employee.phone)
default:
break
}
}Handling Deselection
If you're maintaining selection state (like a master-detail interface), you may need to know when a row is deselected.
func didDeselectItem(_ dataTable: SwiftDataTable, indexPath: IndexPath) {
// Clear the detail view or reset selection state
detailViewController?.clear()
}For more delegate methods (header taps, custom sizing, and more), see Delegate Reference.