2

I have a custom button in my collection view cell. I just want to pass indexPath to it but I am getting "unrecognized selector error"

Here is my code

cell.showMapButton.addTarget(self, action: #selector(testFunc(indexPath:)), for: .touchUpInside)

and the function is

func testFunc(indexPath: IndexPath){
    print("Testing indexPath \(indexPath)")
}

If I remove the indexPath argument it works fine and the function gets called but I need that argument so please help me in resolving this issue.

Krunal
  • 77,632
  • 48
  • 245
  • 261
Moaz Khan
  • 1,272
  • 1
  • 13
  • 28
  • You can use a delegate pattern or a closure. See answers [here](https://stackoverflow.com/questions/28659845/swift-how-to-get-the-indexpath-row-when-a-button-in-a-cell-is-tapped/38941510#38941510) – Paulw11 Aug 01 '17 at 08:31
  • 1
    You cannot use a custom parameter in a target / action pattern. The only supported argument is the sending UI element, the button. – vadian Aug 01 '17 at 08:56

2 Answers2

1

You can pass UIButton instance with target selector parameters for button action.

try with following code:

Add/replace below code, belongs to collection view cell into your collection view data source method - cellForRowAtIndexPath

cell.showMapButton.tag = indexPath.row
cell.showMapButton.addTarget(self, action: #selector(testFunc(button:)), for: .touchUpInside)

For Swift 4 - define your selector function using @objc, like below.

@objc func testFunc(button: UIBUtton){
    print("Index = \(button.tag)")    
}
Krunal
  • 77,632
  • 48
  • 245
  • 261
1

In the addTarget(:action:for:) method for UIButton, the action can at most accept a single UIButton or any of it's superclass as parameter. If you need the indexPath of your button, you need to make it a property of your UIButton by subclass or other means. My way of doing it is to create a subclass of UIButton that have indexPath as it's property:

class ButtonWithIndexPath: UIButton {
    var indexPath:IndexPath?
}

Then add target as normal:

cell.showMapButton.addTarget(self, action: #selector(testFunc(button:)), for: .touchUpInside)

Not forgetting to set the indexPath of your button to that of which ever cell it is in

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! myCell
    cell.button.indexPath = indexPath
    ...
    return cell
}

And cast it into it's custom subclass in the function to read the indexPath:

func textFunc(button: UIButton) {
    let currentButton = (button as! ButtonWithIndexPath)
    print(currentButton.indexPath)
}
Ben Ong
  • 913
  • 1
  • 10
  • 25