0

I added a button @IBOutlet weak var cellButton: UIButton! in my custom tableViewCell class and an action of the button in my tableView controller

 @IBAction func cellButtonTap(_ sender: UIButton) {

      performSegue(withIdentifier: "goToMap" , sender: self)

    }

what I need to do is to pass data to another viewController but is important to know on which cell the button has been pressed, so how can I tell my method prepare

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if segue.identifier == "goToMap"...//HERE I DON'T KNOW HOW TO DO

}

on which cell the button has been pressed? I'm a beginner and I've been looking for a solution for two days but I have not found it yet

Faysal Ahmed
  • 7,501
  • 5
  • 28
  • 50
fisherM
  • 177
  • 1
  • 3
  • 14
  • Just set tag of your cell and when you press cell check the tag of cell to know which cell is being pressed – Muhammad Shauket Jan 12 '18 at 16:14
  • Use a protocol in your custom cell. Here is an example: https://medium.com/@aapierce0/swift-using-protocols-to-add-custom-behavior-to-a-uitableviewcell-2c1f09610aa1 – rmickeyd Jan 12 '18 at 17:29

2 Answers2

1

You can do it with a "call back" closure...

class MyTableViewCell: UITableViewCell {

    var didButtonTapAction : (()->())?

    @IBAction func cellButtonTap(_ sender: UIButton) {
        // call back closure
        didButtonTapAction()?
    }

}

in your table view controller, add a class-level variable:

var tappedIndexPath: IndexPath?

and then your table view cell setup becomes:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyTableViewCell

    // set labels, colors, etc in your cell

    // set a "call back" closure
    cell.didButtonTapAction = {
        () in
        print("Button was tapped in cell at:", indexPath)

        // you now have the indexPath of the cell containing the
        // button that was tapped, so
        // call performSegue() or do something else...

        self.tappedIndexPath = indexPath
        performSegue(withIdentifier: "goToMap" , sender: self)
    }

    return cell
}

and, in prepare:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if segue.identifier == "goToMap" {
         // do what you need based on the row / section
         // of the cell that had the button that was tapped, such as:

        if let vc = segue.destination as? MyMapViewController {
              vc.myData = self.dataArray[self.tappedIndexPath.row]
        }

    }

}
DonMag
  • 69,424
  • 5
  • 50
  • 86
0
  1. Are you sure you need a button at all? Normally it is happened through table view selection delegate.

  2. If you need a button, you need to provide a way to identify what button was pressed. If you have simple one-dimensional array of items to present, simplest method is to setup button's tag to index

Like:

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "<id>", for: indexPath) as? Cell else { return UITableViewCell() }
        cell.button.tag = indexPath.row
        //...
        return cell
    }

then it will better to trigger segue with button as sender:

 @IBAction func cellButtonTap(_ sender: UIButton) {
      performSegue(withIdentifier: "goToMap" , sender: sender)
 }

And you can get you data:

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "goToMap", let index = (sender as? UIView)?.tag {

        }

}
MichaelV
  • 1,231
  • 8
  • 10
  • 1
    Using a tag to represent an index path is a poor choice. If the table view allows for rows to be deleted, inserted, or moved, the tag will be wrong. – rmaddy Jan 12 '18 at 16:56
  • As I said it works in simplest cases. Similar limitations can be with any "button in the cell" solutions, such as blocks, etc. – MichaelV Jan 12 '18 at 17:11
  • No, proper solutions do not have limitations. – rmaddy Jan 12 '18 at 17:15
  • It is philosophical question. You can always imagine the edge-case when when previous reasonable solution stop working. But usually good developer estimate how his solution going to be used and use simplest approach. – MichaelV Jan 12 '18 at 17:23