Programming a UIButton is not working in Swift 4 Xcode 9 Beta 6, Cannot add target

Olivier  picture Olivier · Aug 20, 2017 · Viewed 22.9k times · Source

In the past I had no problem creating a UIButton programmatically, but ever since I've been using Xcode 9 and Swift 4, I cannot find a way to make this error go away.

//Adding target to UIButton
func PositionStartButton(xOffset: Float){
    StartButton.frame = CGRect(x: Int(0 - 40 + xOffset), y: 0, width: 80, height: 80)
    StartButton.setImage(#imageLiteral(resourceName: "Logo_Final_WHITE_Face"), for: .normal)
    StartButton.addTarget(self, action: "pressButton:", for: .touchUpInside)
    ScrollView.addSubview(StartButton)

}

//The target function
func pressButton(_ sender: UIButton){
    print("\(sender)")
}

Error Message: 'NSInvalidArgumentException', reason: '-[Playing.MainMenuViewController pressButton:]: unrecognized selector sent to instance 0x10440a6b0'

Answer

OOPer picture OOPer · Aug 21, 2017

Two points.

First, since Swift 2.2 (bundled with Xcode 7.3, released more than a year ago), recommended selector notation is #selector(...). With using the notation, you may get more useful diagnostic messages, than using other notation.

(You should not ignore any warnings displayed with recommended settings.)

Seconde, in Swift 4, you need to explicitly annotate methods invoked through selector with @objc. (In very limited cases, Swift implicitly applies the notation, but not many.)

So, your code shown should be:

//Adding target to UIButton
func PositionStartButton(xOffset: Float){
    StartButton.frame = CGRect(x: Int(0 - 40 + xOffset), y: 0, width: 80, height: 80)
    StartButton.setImage(#imageLiteral(resourceName: "Logo_Final_WHITE_Face"), for: .normal)
    StartButton.addTarget(self, action: #selector(self.pressButton(_:)), for: .touchUpInside) //<- use `#selector(...)`
    ScrollView.addSubview(StartButton)

}

//The target function
@objc func pressButton(_ sender: UIButton){ //<- needs `@objc`
    print("\(sender)")
}

This is not critical, but you should better follow a simple coding rule of Swift -- only type names are capitalized.

Better rename your PositionStartButton, StartButton and ScrollView, if you think you may have another chance to show your code publicly.