You need not access the button using tag and then set Selector
for each cell. I believe you can achieve much cleaner approach
Step 1:
In your Custom cell, drag the IBAction
from button in cell to your custom cell.
@IBAction func buttonTapped(_ sender: Any) {
//wait for implementation
}
Step 2:
In your custom cell, now declare a protocol
protocol CellsProtocol : NSObjectProtocol {
func buttonTapped(at index : IndexPath)
}
and while in being same class, create few variables as well.
weak var delegate : CellsProtocol? = nil
var indexPath : IndexPath! = nil
we will see the usage of these variables soon :)
Step 3:
Lets get back to IBAction
we dragged just now
@IBAction func buttonTapped(_ sender: Any) {
self.delegate?.buttonTapped(at: self.indexPath)
}
Step 4:
Now you can get back to your UITableViewController
and confirm to the protocol you declared just now
extension ViewController : CellsProtocol {
func buttonTapped(at index: IndexPath) {
//here you have indexpath of cell whose button tapped
}
}
Step 5:
Now finally update your cellForRowAtIndexPath
as
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : MyTableViewCell = ;
cell.indexPath = indexPath
cell.delegate = self
}
}
Thats it :) Now you have a button action which tells you, button in which cell tapped :) Hope it helps :) This is more generic approach, because even if you have multiple uicomponents
you can still use this approach.
EDIT 1:
In comments below rmaddy pointed out that having a indexPath as a property cell might lead to issues and cell should not care to know its indexPath and protocol should be modified to return the cell rather than returning the index path.
Quoting comment :
Not necessarily. You are assuming reloadData is being called. You can
have a visible cell and then insert a row above it. That visible cell
is not updated and its indexPath is not different but the cell's
indexPath property that you have is not updated. Use the cell itself
as the argument. It's much better than passing the index path. If the
index path is needed by the delegate, the delegate can ask the table
view what the cell's current index path is. A cell should never care
or know what its index path is.
The statement above makes sense especially the fact that A cell should never care or know what its index path is. Hence updating my answer below
Step 1:
Go ahead and delete the indexPath property in cell :)
Step 2:
Modify protocol to
protocol CellsProtocol : NSObjectProtocol {
func buttonTapped(in cell : UITableViewCell)
}
Step 3:
Modify your IBAction as
@IBAction func buttonTapped(_ sender: Any) {
self.delegate?.buttonTapped(in: self)
}
Step 4:
Finally modify your protocol confirmation in your ViewController to
extension ViewController : CellsProtocol {
func buttonTapped(in cell: UITableViewCell) {
let indexPath = self.tableView.indexPath(for: cell)
//here you have indexpath of cell whose button tapped
}
}
Thats it :)