2

In Swift 2 this used to work (I have left out table view methods intentionally)...

 import Foundation
 import UIKit

 private extension Selector {
    static let didTapButton = #selector(TableVC.buttonTapped(_ :))

 }

 class TableVC: UITableViewController{

     override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
         let btnAccView:UIButton = UIButton(frame: CGRectMake(0, 0, 27, 27))
         btnAccView.addTarget(self, action: .didTapButton, forControlEvents: UIControlEvents.TouchUpInside)
         btnAccView.tag = indexPath.row
     }


     func buttonTapped(sender: UIButton){
         print("button tapped at row \(sender.tag)")
     }

 }

In Swift 3 this causes the error : "TableVC has no member buttonTapped".

I just need to write a selector that takes an argument. I have tried fiddling with the syntax in every way I can think of but nothing has worked. Thanks for your help

MikeG
  • 3,745
  • 1
  • 29
  • 51
  • 1
    According to [this question](http://stackoverflow.com/q/24814646/5513562)'s answer, it can't be done. – Andrew Bennet Nov 09 '16 at 17:33
  • 1
    http://fuckingclosuresyntax.com/ http://fuckingswiftblocksyntax.com/ – Sunil Chauhan Nov 09 '16 at 17:37
  • Just for the record, marking a question as a duplicate and not referencing the original question is of absolutely no use to anyone. If it's a duplicate where is the original? – GED125 Feb 01 '17 at 00:11

3 Answers3

3

First of all, you need to modify buttonTapped so that the first argument label is suppressed. Insert an underscore before the internal argument label so that it looks like this:

func buttonTapped(_ sender: UIButton) {

Before, its method signature was TableVC.buttonTapped(sender:), and now its signature will be TableVC.buttonTapped(_:). You might have to remove the space between the underscore and the colon in your extension, but it should work after that.

As a side note, is there any particular reason you're using an extension on Selector here? That extension model is most useful typically with stuff like notification names that can be easily misspelled, resulting in tricky bugs. Since the Swift compiler automatically validates #selector declarations no matter where they're placed, you can just put it right into your code—no extension necessary.

Bob
  • 910
  • 1
  • 8
  • 12
1

You can save yourself some grief by letting the compiler infer some of the function signature. In your case...

class TableVC: UIViewController {
    func buttonTapped(sender: UIButton) { /*...*/ }
}

You can refer to it from outside the TableVC class as either:

  • #selector(TableVC.buttonTapped(sender:))
  • #selector(TableVC.buttonTapped)

The second works because there's only one buttonTapped function on TableVC, so the compiler doesn't need the full signature to disambiguate it.

From code inside of TableVC you can simplify it a step further and just use #selector(buttonTapped), because at that point you're in the class scope and it can safely infer a method of the class.

(The #selector(TableVC.buttonTapped(_:)) line you're using works only if your method is declared as func buttonTapped(_ sender: UIButton). For your use case, it doesn't matter whether the sender parameter has an argument label or not — you just have to be consistent about it between your func declaration and your #selector expression.)

And as @Bob notes, there's no need for the Selector extension, because the compiler already validates the selector.

rickster
  • 124,678
  • 26
  • 272
  • 326
0

Use following way to implement selector for button action:

import UIKit
class MyViewController: UIViewController {
    let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))

    override init?(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        let action = #selector(MyViewController.tappedButton)
        myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)
    }

    func tappedButton(sender: UIButton?) {
        print("tapped button")
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}
Devanshu Saini
  • 765
  • 5
  • 24