GitHub

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:

PropertyWhat It MeansExample
indexPath.sectionThe row (0-indexed)Row 0 = first data row
indexPath.itemThe 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

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.