35
votes

I have no idea what I am doing wrong. I am also quite new to programming so I am not very good at debugging. This was a test app so that I can see how swift ties in with app development. So far, I have got this:

class ViewController: UIViewController, UITextViewDelegate {

    var textView: UITextView!

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        var widthField = self.view.bounds.size.width - 10
        var heightField = self.view.bounds.size.height - 69 - 221
        var textFieldString: String! = ""
        //Set up text field
        self.textView = UITextView(frame: CGRectMake(5, 64, widthField, heightField))
        self.textView.backgroundColor = UIColor.redColor()
        self.view.addSubview(self.textView)
        //Set up the New button
        var newButtonString: String! = "New Note"
        var heightButton = 568 - heightField - 1000
        let newButton = UIButton(frame: CGRect(x: 5, y: 5, width: widthField, height: 50)) as UIButton
        UIButton.buttonWithType(UIButtonType.System)
        newButton.setTitle(newButtonString,forState: UIControlState.Normal)
        newButton.backgroundColor = UIColor.redColor()
        newButton.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(newButton)

    }

    func buttonAction() {
        println("tapped button")
    }
}

I am getting the error "Unrecognized selector sent to instance" when I press the button in the iOS simulator. The app opens fine but whenever the button is pressed, it just crashes.

11
remove the semicolon from this "buttonAction:", becase you don't have any buttonAction fucntion/selector which works with one parameter. your function works with zero parameter (), and those are definitely different.holex
This can also happen if you add a target to a private function - it would be nice if there was a stronger typed system to catch this.Chris Conover
To OP: If you see one of the answers below helpful and your question was already resolved, please consider accepting it by tapping the checkmark just below the vote counter.Blaszard
As someone said in the previous answers, for me the problem was that too many previous IBActions were still linked to that button. Check this screenshot. On my Touch up inside there were multiple IBActions. Just delete the old ones and have only the one you use.iGotInTroubles

11 Answers

37
votes
func buttonAction(){...

should be

func buttonAction(sender:UIButton!)
{
    println("tapped button")
}

Because of newButton's action: "buttonAction:" so.

13
votes

If you have a colon in the selector name (buttonAction:) you have to have the sender as a n argument for the buttonAction function, if you don't have any colon in the name the sender will not be sent.

13
votes

Got this working by adding an "_ " before the argument.. refer to snippet below

func buttonAction(sender:UIButton)  // this was throwing the error "unrecognized selector sent to instance"
{
    println("tapped button")
}

func buttonAction(_ sender:UIButton)  // added an "_ " before sender
{
    println("tapped button")
}
9
votes

There are two other causes I ran into which can lead to this type of error:

1) When the first argument to addTarget does not inherit from NSObject. For example this will not work:

class MyClass {
    init(button: UIButton) {
        button.addTarget(
            self,
            action: Selector("onClick:"),
            forControlEvents: UIControlEvents.TouchUpInside)
    }

    func onClick(sender: AnyObject?) {
        //Gotcha!
    }
}

}

To fix just change to:

class MyClass: NSObject
...

2) When you don't hold onto an explicit reference for the instance with the selector. For example if using the same above code:

func crashMe() {
    var delegate = MyClass(button)
}

Swift seems to garbage collect "delegate" even though it's listening to button, hence a crash will occur. To fix, change to something like this:

func crashMe() {
    self.delegate = MyClass(button)
}

I also ran into BOTH the "private" and "crashMe" versus "crashMe:" issues while developing my app... Hence taking the time to write this post to sum up the traps you'll run into. :)

7
votes

The syntax should be

@IBAction func buttonAction(_ sender: UIButton) {
     print('tapped')
 }

Either the syntax is the issue or

The Button on the storyboard has several registered actions to it. To find out just right click button and you should be able to see how many connection there are

if the touch up inside has more than one connection delete one. This is because if you have multiple connections and you click on the control the compiler will be confused as to which one it should implement

6
votes

I know this is too late to answer this question but I'm answering this for anyone who stumbles into a similar type of issue. Recently I had an "Unrecognised selector sent to instance" issue which took me a whole day to debug. So I'm listing possible causes for the issue hope this helps someone facing this error.

Usually, this error is thrown when you pass a selector to an instance but that selector isn't there. In simple words, it's like someone gives a courier guy an address to deliver but that address is inexistent.

How to debug: 1. First, check all of your @objc marked methods: when you call an @objc marked method using #selector() syntax the method signature should be exactly the same.

  1. This type of error can also arise when you are making an invalid casting of the object. This was my case. I was setting an attributed string to a label and in the attributes passed an enum case (TextProperty.title) instead of (TextProperty.title.font). so the font variable returns a UIFont object.

since the keys in the attribute, dictionary expect "Any" Xcode didn't throw an error. So the font attribute was expecting a UIFont but got TextProperty enum case instead. So do check if you are doing an invalid cast in your code.

  1. There can be a memory leak in your code. eg: you could be sending a selector to an instance but that selector is wiped out of memory.

These are the cases that I could think of. If you have something that can help you are welcome for suggestions.

2
votes

when using performSelector() methods your method (matching the selector) should be marked as @objc

{  
    //...
    performSelector(Selector("myMethod"), withObject: nil, afterDelay: 0.3)
    //...

    // or in swift 2.2
    performSelector(#selector(ClassName.myMethod), withObject: nil, afterDelay: 0.3)
    //

    // or in swift 3
    perform(#selector(ClassName.myMethod), with: nil, afterDelay: 0.3)
    //

}

@objc private func myMethod() { }
1
votes

Adding an @IBAction function to your code and then deleting or renaming it without updating your storyboard will also cause this error.

Look at the selector in the error message:

'-[HelloWorld.ViewController yourActionFunction:]: unrecognized selector sent to instance 0x157e0c830'
                             ^^^^^^^^^^^^^^^^^^

Do you have a function named yourActionFunction? If not, select the storyboard and edit the connections on your control (e.g. button).

0
votes

In your viewDidLoad, notice my Selector is calling my func with the colon.

override func viewDidLoad() {
        super.viewDidLoad()
        // init gesture recognizer swipe right vars
        var rightSwipe = UISwipeGestureRecognizer(target: self, action: Selector("gestureFunc:"))
        rightSwipe.direction = UISwipeGestureRecognizerDirection.Right
        view.addGestureRecognizer(rightSwipe) 
    }

Then make sure that the Selector i.e. func is ready to receive it's swipe:

        // selector from UISwipeGestureRecognizer
        func nextWeapon(gesture: UISwipeGestureRecognizer) {
        println("swipe right")
        }
0
votes

For those who end up in my shoes: If you're creating your button in a static context, ensure you're passing the correct target to UIButton.addTarget(_:action:for:). Passing self will result in passing the type not an instance.

0
votes

In some cases to fix it you will need to go to Build Settings -> Other Linker Flags and then set its value to -ObjC