NSInvalidArgumentException with button tap detection - ios

The app has a screen in which after giving the inputs, I tap OK button and it should perform input validation, if fine, then navigate and pass data back to the previous screen via protocol/delegate, otherwise, block navigation and display a warning pop-up.
This is my viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: "pushView:", forControlEvents: .TouchUpInside)
}
This is the pushView() function:
func pushView() {
//some codes to validate data and perform navigation
}
When I run the app in simulator, it crash when I tap the button and this is the error message:
2016-04-21 00:12:39.976 ToDo List[1795:1253192] -
[ToDo_List.AddReminderController pushView:]:
unrecognized selector sent to instance 0x7fa13ac16c40
2016-04-21 00:12:39.981 ToDo List[1795:1253192]
*** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-
[ToDo_List.AddReminderController pushView:]:
unrecognized selector sent to instance 0x7fa13ac16c40'
There may be an issue with sender or selector but I don't know what it exactly means.

When you add a : to your selector/action name like you have here:
button.addTarget(self, action: "pushView:", forControlEvents: .TouchUpInside)
It means that your selector expects a parameter.
Your pushView() function on the other hand, does not include any parameters, so to iOS/UIKit you are referencing two different things.
The solution is to:
either remove the : from your action like so:
button.addTarget(self, action: "pushView", forControlEvents: .TouchUpInside)
or add a parameter to your pushView() function like so:
func pushView(sender: AnyObject)

Fix selector:
button.addTarget(self, action: "pushView", forControlEvents: .TouchUpInside)
For future remember that latest swift 2.2 syntax has some differences in this.
button.addTarget(self, action: #selector(MyClass.pushView), forControlEvents: .TouchUpInside)

Related

Swift | UIButton causes crash on tap

I added a button on the main screen of the app and on the tap of a button, a new viewcontroller is presented.
This works completely fine in the simulator but as soon as I try in an actual iPhone, it causes the app to crash.
Also, the crash is only caused on the login button while the sign up button made the same way does work perfect
I will leave the code below
var loginButton = UIButton()
var signUpButton = UIButton()
loginButton.setTitle("Login", for: .normal)
loginButton.titleLabel?.textAlignment = .center
loginButton.backgroundColor = appGreenTheme
loginButton.titleLabel?.textColor = .white
loginButton.layer.cornerRadius = 20
loginButton.titleLabel?.font = UIFont.systemFont(ofSize: 20)
loginButton.setBackgroundImage(UIImage(named: "pinkOrangeGradientPDF"), for: .normal)
loginButton.clipsToBounds = true
signUpButton.setTitle("Sign Up", for: .normal)
signUpButton.setTitleColor(.black, for: .normal)
signUpButton.titleLabel?.textAlignment = .center
signUpButton.backgroundColor = .white
signUpButton.titleLabel?.textColor = .black
signUpButton.layer.cornerRadius = 20
signUpButton.titleLabel?.font = UIFont.systemFont(ofSize: 20)
loginButton.addTarget(self, action: #selector(loginButtonTapped1(_:)), for: .allTouchEvents)
signUpButton.addTarget(self, action: #selector(signUpButtonTapped1(_:)), for: .allTouchEvents)
///////////////////////////////////////////////////
#objc func loginButtonTapped1(_ sender: UIButton) {
let nav = UINavigationController(rootViewController: LoginViewController())
self.present(nav, animated: true, completion: nil)
}
#objc func signUpButtonTapped1(_ sender: UIButton) {
let nav = UINavigationController(rootViewController: SignUpViewController())
self.present(nav, animated: true, completion: nil)
}
I also tried with "touchUpInside" events. again it works perfectly in the simulator but not in a physical device.
Any help is welcome.
Below is the error shown in the logs
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SparkGPS.LoginView addTarget:action:forControlEvents:]: unrecognized selector sent to instance 0x13dd4c740'
The answer is in the error message. Somewhere, my guess is in LoginViewController, there is a view of type LoginView. That view is calling addTarget(_:action:for:). LoginView is not subclassed from UIControl and does not have addTarget(_:action:for:). It's causing the crash.
Let me break down the parts of -[SparkGPS.LoginView addTarget:action:forControlEvents:].
The - at the beginning means it's an instance method and not a static or class method.
SparkGPS.LoginView is the module and class. A module is another word for a framework or app. In this case, it looks like you have an app named SparkGPS and a class named LoginView.
addTarget:action:forControlEvents: is Objective-C's name for addTarget(_:action:for:).
Finally, "selector sent to instance" means the variable call a method. Selector is a way to identify a method, and an instance is stored in a variable. For example, in your code you have loginButton.setTitle("Login", for: .normal). This could be worded as setTitle(_:for:) was sent to the instance loginButton.
You can add a tap gesture recogniser to the button itself. It's best practice to use outlets, but this works fine and is useful for other UI components like views or labels too
let loginTapGesture = UITapGestureRecognizer(target: self,
action: #selector(loginButtonTapped1))
loginButton.addGestureRecognizer(loginTapGesture)

Why am I getting an unrecognized selector error?

This code:
override func viewDidLoad() {
super.viewDidLoad()
mqttDataClient.delegate = self
mqttDataClient.connect()
let tableRefresh = UIRefreshControl()
tableView.refreshControl = tableRefresh
tableRefresh.addTarget(tableView, action: #selector(updateTable), for: .valueChanged)
tableRefresh.endRefreshing()
}
#objc func updateTable(){
print("R")
mqttDataClient.publish("control", withString: "sendMovieList")
}
crashes with the following error:
-[UITableView updateTable]: unrecognized selector sent to instance 0x106008a00
I am using Xcode 10 on macOS 10.14. I think I have this set up correctly and I am wondering if it's an issue with the new xCode. I mean the selector is right there, right?
Your updateTable is a method of your view controller, not the table view.
Change:
tableRefresh.addTarget(tableView, action: #selector(updateTable), for: .valueChanged)
to:
tableRefresh.addTarget(self, action: #selector(updateTable), for: .valueChanged)
The target must always be the class that implements the selector.

Unrecognized Selector when Passing Parameter - UIButton in TableView Cell | Swift iOS

I've had this issue before but it usually due to not having a button hooked up in Storyboard or not passing a parameter when the function is expecting one, like most of the existing questions on here seem to suggest. This time however it is neither of those things.
I am creating a button in my TableView Cell by using this code in the CellForRowAt method:
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.addTarget(self, action: Selector(("showPeople:")), for: UIControlEvents.touchUpInside)
button.tag = indexPath.row
cell.addSubview(button)
and I have declared the showPeople method like so:
func showPeople(sender: UIButton) {
print("pressed")
}
When the button is pressed the program crashed with the following message:
showPeople: unrecognized selector sent to instance
But when I declare the method like so (remove the parameter):
func showPeople() {
print("pressed")
}
and change the selector to Selector(("showPeople")) it works fine which I guess means there is an issue with the way I'm passing the parameter. Why would this be happening? The function is expecting a parameter so the : is needed.
Looks like you're missing sender part in your selector.
Try this instead:
button.addTarget(self, action: #selector(ViewController.showPeople(sender:)), for: .touchUpInside)

Selector for different ViewController

Inside an extension for UIButton, I create a button and add its target.
extension UIButton {
convenience init(target: AnyObject) {
self.init(type: .system)
self.addTarget(target, action: Selector("setLang:"), for: .touchUpInside)
}
}
In ViewController, when using the custom init function to create the button, as target, I pass self.
This worked fine before upgrading my code to Swift 3. Now, however, I receive an error when tapping the button saying:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyApp.ViewController setLang:]: unrecognized selector sent to instance xxx
Inside ViewController there is the following function declared that is supposed to be called:
func setLang(button: UIButton) {
//...
}
Any ideas?
Thanks in advance!
i found that solution from apple developer Forums. This may help you.
selectionButton.addTarget(self, action: #selector(SingleQuestionViewController.selected(_:)), for: .touchUpInside)
// try like this , i hope it will work for you.
self.addTarget(target, action: NSSelectorFromString("setLang:"), for: .touchUpInside)
Found the problem. Instead of declaring the function like I did before, I need to do it the following way:
func setLang(_ button: UIButton) {
//...
}
Hope this helps other peeps.

Unrecognized selector sent to instance Swift 2.1 - Selector issues [duplicate]

I am having problems with trying to get a UIButton to work when the user presses it. I keep getting an error saying: unrecognised selector sent to instance
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: "buttonClick", forControlEvents: UIControlEvents.TouchUpInside)
button.setTitle("Print", forState: UIControlState.Normal)
button.font = UIFont(name: "Avenir Next", size: 14)
button.backgroundColor = UIColor.lightGrayColor()
self.view.addSubview(button)
}
func buttonClick(Sender: UIButton!)
{
myLabelInfo.text = "Hello"
}
For a Swift method such as func buttonClick(Sender: UIButton) what is the correct string to pass to addTarget method for the selector? Is it "buttonClick", "buttonClick:", "buttonClickSender:" or something else?
You're using an invalid method signature for the action. You're supplying buttonClick, but the method has an argument, so the signature should be buttonClick:
button.addTarget(self, action: "buttonClick:", forControlEvents: UIControlEvents.TouchUpInside)
For more information about how to format your selectors, you can refer to the accepted answer in the post linked below. The code used in this post may be Objective-C, but all its lessons can be applied here as well.
Creating a selector from a method name with parameters
And as a side note, this code would also be valid if you used Selector("buttonClicked:") as the action, but you don't have to because string literals can be implicitly cast to the Selector type.
Quoting from Using Swift with Cocoa and Objective-C
An Objective-C selector is a type that refers to the name of an
Objective-C method. In Swift, Objective-C selectors are represented by
the Selector structure. You can construct a selector with a string
literal, such as let mySelector: Selector = "tappedButton:". Because
string literals can be automatically converted to selectors, you can
pass a string literal to any method that accepts a selector.
Swift < 2.2
In Swift < 2.2 the selector method cannot be private (unrecognized selector error).
Prefered (by Apple) notation is the string "methodWithParam:" notation.
Troubleshooting: if you have troubles with NSTimer selector, maybe your class should be a subclass of NSObject.
Swift >= 2.2
Use the #selector notation. Read more here: https://github.com/apple/swift-evolution/blob/master/proposals/0022-objc-selectors.md
For private methods you can use the #objc method modifier, like this: #objc private func timerTick(timer: NSTimer).
No need for subclassing NSObject anymore!
The notation for Swift > 2.2 would be:
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(YourClass.yourMethod(_:)))
Worked for me so far (Xcode 7.3)
You need to pass it an actual Selector. Try using this line instead:
button.addTarget(self, action: Selector("buttonClick:"), forControlEvents: UIControlEvents.TouchUpInside)
You also need the : at the end of the selector name because you have 1 argument. This is the same as typical Obj-C selector naming.
You have missed the colon while specifying selector.so the line should be
button.addTarget(self, action: Selector("buttonClick:"), forControlEvents: UIControlEvents.TouchUpInside)
I had the same problem - the solution ended up being prefixing the method I wanted the button to execute on click with #objc, to expose it in the Objective-C header file and thereby the Objective-C runtime.
Like:
#objc func buttonClick(Sender: UIButton!)
{
myLabelInfo.text = "Hello"
}

Resources