Why am I getting an unrecognized selector error? - ios

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.

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)

Assign 'action' dynamically in uibutton.addTarget

please bear with me, as I'm new to swift -4 weeks old-.
I've created the following 2 functions in fileA.swift
func custombttn(theSelector:Selector)-> UIButton{
let bttn = UIButton(frame: CGRect(x:20, y:400, width:200, height:30))
bttn.setTitle("tap this button", for: UIControlState.normal)
bttn.backgroundColor = UIColor.black
bttn.setTitleColor(UIColor.magenta, for: UIControlState.normal)
bttn.addTarget(bttn, action: theSelector, for: UIControlEvents.touchUpInside)
return bttn
}
func customtxtfld() -> UITextField{
let txtField = UITextField(frame: CGRect(x:20, y:360, width:200, height:30))
txtField.borderStyle = UITextBorderStyle.roundedRect
txtField.backgroundColor = UIColor.magenta
txtField.placeholder = "Do you like me now..?"
return txtField
}
The reason behind the custombttn(theSelector:Selector), is that i want to pass the function dynamically to the button in my viewcontroller file.
Now, moving the fileB.swift, I have the following code...
class TabOneViewController: UIViewController{
let txt = customtxtfld()
let bttn = custombttn(theSelector: #selector(updatetxt))
override func loadView() {
super.loadView()
view.addSubview(txt)
view.addSubview(bttn)
}
func updatetxt(){
txt.text = "hello, you!"
}
}
Here is where things get tricky, when I attempt to build, I don't get any error (not even a warning). However, when I run the app, and tap the bttn in fileB.swift, I get the following error during runtime:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[UIButton updatetxt]:
unrecognized selector sent to instance 0x7f8453415670'
If I have 2 or more functions in my fileB.swift that I wish to assign dynamically to the action part of the addTarget, is there any way I can pass the selector dynamically to a button..?
Appreciate your time and assistance. Please let me know if I need to explain something further.
It's crashing because your button target is wrong.
func custombttn(target:Any, theSelector:Selector)-> UIButton{
let bttn = UIButton(frame: CGRect(x:20, y:400, width:200, height:30))
bttn.setTitle("tap this button", for: UIControlState.normal)
bttn.backgroundColor = UIColor.black
bttn.setTitleColor(UIColor.magenta, for: UIControlState.normal)
bttn.addTarget(target, action: theSelector, for: UIControlEvents.touchUpInside)
return bttn
}
And use it like this
class TabOneViewController: UIViewController{
let txt = customtxtfld()
override func loadView() {
super.loadView()
view.addSubview(txt)
let bttn = custombttn(target:self, theSelector: #selector(updatetxt))
view.addSubview(bttn)
}
func updatetxt(){
txt.text = "hello, you!"
}
}
Yes, you can. The issue here is that you passed the button itself as the target for the action. Just pass the correct target when adding the action, which in this case is the instance of your view controller.

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 0x7f90f1f04180

I'm a newbie to swift. I'm using xcode version 8 beta 4. I'm having an error whenever I scroll through my Date Picker. I have read a very similar problem, but the answer there is not fixing my problem. Below is my code:
func textFieldDidBeginEditing(_ textField: UITextField) {
let datePicker = UIDatePicker()
textField.inputView = datePicker
datePicker.addTarget(self, action: Selector("datePickerChanged:"), for: .valueChanged)
}
func datePickerChanged(sender: UIDatePicker){
let formatter = DateFormatter()
formatter.dateStyle = .long
dateLog.text = formatter.string(from: sender.date)
}
when I click on my textfield the UIDatePicker is showing up just fine, but when I start to scroll through the dates, it gives me the following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyApp.ViewController datePickerChanged:]: unrecognized selector sent to instance 0x7f90f1f04180'
Selector(String) is deprecated. You should start using the new syntax #selector.
Also, the colon at the end is not needed.
So, your code should look like this:
datePicker.addTarget(self, action: #selector(datePickerChanged),
for: .valueChanged)
change the Selector to #selector
change for to forControlEvents
change .valueChanged to .ValueChanged
datePicker.addTarget(self, action: #selector(yourClass.datePickerChanged), forControlEvents: .ValueChanged)

NSInvalidArgumentException with button tap detection

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)

Resources