4

I've seen that, this is a common issue but i couldn't find any solution for myself.

Here is the code:

class ButtonViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(button)
    }

    func exmp(sender: UIButton) {
        print("hello world")
    }

    let button: UIButton = {
        let but = UIButton(frame: CGRect(x: 33, y: 33, width: 33, height: 33))
        but.setTitle("-", for: .normal)
        but.titleLabel?.textColor = UIColor.white
        but.layer.cornerRadius = 10
        but.backgroundColor = UIColor.red
        but.addTarget(ButtonViewController.self, action: #selector(ButtonViewController.exmp(sender:)), for: .touchDown)
        return but
    }
}

Issue: The red button appears but when i click it i get the "Unrecognized selector sent to class" error.

Any help is appreciated! Thanks.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Unal Celik
  • 186
  • 3
  • 13

2 Answers2

9

You are getting Unrecognized selector sent to class because you have set the wrong target. The target should be self and not ButtonViewController.self:

but.addTarget(self, action: #selector(ButtonViewController.exmp(sender:)), for: .touchDown)

Your #selector works, but for Swift 3 you should write the action as func exmp(_ sender: UIButton) { making the selector #selector(exmp(_:)). Note: whether or not you rewrite exmp, you can simplify the selector to just #selector(exmp).

vacawama
  • 150,663
  • 30
  • 266
  • 294
  • 2
    I have filed a bug on Swift with regard to this. The compiler should not be helping you with `#selector` syntax on the one hand but then letting you set the wrong target on the other. "Unrecognized selector" should be a dead letter! – matt Jan 02 '17 at 15:55
  • Thanks for your answer but there is a different problem now which is " Command failed due to signal: Segmentation fault: 11". – Unal Celik Jan 03 '17 at 14:08
0

So i've been looking around for this issue for 2 days. The right addTarget method must be like this:

but.addTarget(self, action: #selector(ButtonViewController.exmp(sender:)), for: .touchDown)

But there was still one more problem for me which is "Command failed due to signal: Segmentation fault: 11".

When i tried to create my button in viewDidLoad() method there was no error. So i thought that may be something with where the button is created or not. And i put lazy var instead of let while creating my button.

Still, as a beginner i dont really know what "layz var" is. I just know that causes my button created, only when it's called. It'd be nice if someone enlightens me and other beginners around here about lazy vars. Thanks.

Final Solution

override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(button)
}

func exmp(sender: UIButton) {
    print("hello world")
}

lazy var button: UIButton = {
    let but = UIButton(frame: CGRect(x: 33, y: 33, width: 33, height: 33))
    but.setTitle("-", for: .normal)
    but.titleLabel?.textColor = UIColor.white
    but.layer.cornerRadius = 10
    but.backgroundColor = UIColor.red
    but.addTarget(self, action: #selector(ButtonViewController.exmp(sender:)), for: .touchDown)
    return but
}()
Unal Celik
  • 186
  • 3
  • 13
  • 1
    lazy vars are initialized the first time they are used. The reason that is important here is that `self` isn't available to be used in the initialization of properties until the class has been initialized. By making your var lazy, you get around that restriction by deferring initialization of that property until the first time it is used. At that time, the object will be initialized and `self` can be used. – vacawama Jan 03 '17 at 15:54