Adding a Target to a Button Programmatically Throws an Error "Unrecognized Selector Sent to Class"

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



Leave a reply



Submit