Adding a target to a button programmatically throws an error unrecognized selector sent to class
It's actually all a matter of timing. You are declaring an instance property along with a define-and-call function that initializes that property, and you proceed to say button.addTarget(self...
in that function. The question then is: when will that function's code run? Incredibly, that matters a lot, so much so that it actually changes the meaning of self
.
When you say let
to make this declaration, the code runs at a time when the instance does not yet exist. The instance is exactly what we are in the process of forming at that moment; it isn't "cooked" yet. In fact, unbeknownst to you, self
at that moment means the UIButton class! Therefore the resulting target-action is invalid; you have no class method postComment
; it's an instance method (rightly). And so later on when you tap the button and we try to say postComment
to the class, we crash. "Unrecognized selector sent to class", exactly as you say.
On the other hand, when you say lazy var
, the code is not called until after the instance self
does exist, self
means the instance, and all is well.
It's terribly confusing to beginners, and to not-so-beginners; even after pointing out the problem, I've proceeded to make exactly the same mistake myself. In my opinion the compiler should catch this and stop you, but it doesn't. I've filed a bug: http://bugs.swift.org/browse/SR-4865
Swift: Unrecognized selector sent to class, buttons target in NSObject class
Update
If you could not get instance of HeaderViews
. then just change getAvatar
to static funciton.
static func getAvatar(_ sender: UIButton!) {
print("Change Avatar tapped")
}
Origin
You should not use self
as target in static function.
Because this self
means HeaderViews
.
Passing instance to function as target.
Ex:
static func setUpHeaderForProfileView(user: User, in instance: HeaderViews) -> UIView {
let view = UIView(frame: CGRect(x: 0, y: 0, width: screen.width, height: 100))
let changeAvatarButton = UIButton(frame: CGRect(x: (screen.width / 2) - 50, y: avatarImageView.frame.maxY + 10, width: 100, height: 20))
changeAvatarButton.addTarget(instance, action: #selector(getAvatar(_:)), for: .touchUpInside)
view.addSubview(changeAvatarButton)
return view
}
UIButton unrecognized selector sent to instance
Try this
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! ClinicListCell
cell.title.text = clinicNames[indexPath.row]
cell.subTitle.text = clinicSubs[indexPath.row]
cell.backgroundImageView.image = UIImage(named: clinicImages[indexPath.row])
cell.profileBtn.tag = indexPath.row
cell.profileBtn.addTarget(self, action: #selector(YourViewController.profileBtnClicked(sender:)), for: UIControlEvents.touchUpInside)
return cell
}
class func profileBtnClicked(sender:UIButton) {
print("Selected")
}
How to add an action to a UIButton that is in another class
The best option would be to add the target in your controller and then call a method in your toolbarWrapper
on button press. But if you really need to keep this design, you should have a strong reference to your toolbarWrapper
in your controller class, otherwise your toolbarWrapper
is deallocated and nothing gets called. Also, the buttonTapped(_:)
method does not need to be static. Thus, in your controller:
class Controller: UIViewController {
var toolbarWrapper: CustomToolbarWrapper?
override func viewDidLoad() {
toolbarWrapper = CustomToolbarWrapper(view: view, target: self)
let toolbar = toolbarWrapper.toolbarView
view.addSubview(toolbar)
... Other code ...
}
}
And in your wrapper:
class CustomToolbarWrapper {
var toolbarView: UIView
init(view: UIView, target: Any) {
let height: CGFloat = 80
toolbarView = UIView(frame: CGRect(x: 0, y: view.frame.height - height,width: view.frame.width, height: height))
let button = UIButton()
... Some button layout code ...
button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
toolbarView.addSubview(button)
}
@objc func buttonTapped(_ sender: Any) {
print("button tapped")
}
}
Programmatically set UIButton action throws exception
Given that you are passing self
as the button target of a button in another class, and given that the error indicates that the button handler is trying to call the action method on the wrong target (an NSDictionary
), it's a good bet that self
was deallocated after making itself the button's target. And now some random object is in the same memory location.
This can be confirmed by implementing the dealloc
method on whatever class self
is in your posted code. Then see if this dealloc
is reached before the button is tapped on.
If so you know that self
is being deallocated to soon. You need to keep a strong reference to it so it isn't deallocated too soon.
Swift 3: Unrecognized selector sent to instance Xcode 8
If you are using swift
3 your selector
should be like this
#selector(self.handleTap(recognizer:))
+[UIView onBackgroundRequest:]: unrecognized selector sent to class
How is the action on your button in class StartTableHeaderView
that calls onBackgroundRequest:
set up? Are you using Interface Builder or doing it in code?
If in code, can you post that?
I think you may not be posting the notification like you think. Put a breakpoint inside StartTableHeaderView
onBackgroundRequest:
and see if it is ever triggered.
The error is telling you that onBackgroundRequest:
is not found, not onBackgroundRequested:
.
Related Topics
How to Set Navigationview Background Colour in Swiftui
iOS Revoke Location Services Permission Programmatically
Aes 128 Message Decryption -- Swift, iOS
How to Get Stack Trace Error in Swift
Swift Calling Setnavigationbarhidden But View Wont Move to Top
The Meaning of "Withevent" in Swift, and Parameter Modifiers in General
Can't Set Calayer's Border Color
Why Do I Get an Mkerrordomain Error When Doing a Local Search
Swift 3 - Passing Data Between a View Controller and After That to Another 2
iOS Development App Startup Crash
How to Debug Swift Playgroundbook
Delete Image from Photo Gallery
Target Is Not Found, Please Reconnect the Device, Xcode:Device Support File
How to Remove Single Object in Array from Multiple Matching Object