The easiest and most efficient way in Swift is a callback closure.
- Subclass
UITableViewCell
, the viewWithTag way to identify UI elements is outdated. -
Set the class of the custom cell to the name of the subclass and set the identifier to
ButtonCellIdentifier
in Interface Builder. -
Add a
callback
property. -
Add an action and connect the button to the action.
class ButtonCell: UITableViewCell { var callback : (() -> Void)? @IBAction func buttonPressed(_ sender : UIButton) { callback?() } }
-
In
cellForRow
assign the callback to the custom cell.override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonCellIdentifier", for: indexPath) as! ButtonCell cell.callback = { print("Button pressed", indexPath) } return cell }
-
When the button is pressed the callback is called. The index path is captured.
Edit
There is a caveat if cells can be added or removed. In this case pass the UITableViewCell
instance as parameter and get the index path from there
class ButtonCell: UITableViewCell {
var callback : ((UITableViewCell) -> Void)?
@IBAction func buttonPressed(_ sender : UIButton) {
callback?(self)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonCellIdentifier", for: indexPath) as! ButtonCell
let item = dataSourceArray[indexPath.row]
// do something with item
cell.callback = { cell in
let actualIndexPath = tableView.indexPath(for: cell)!
print("Button pressed", actualIndexPath)
}
return cell
}
If even the section
can change, well, then protocol/delegate may be more efficient.