Search code examples
swiftuibuttonselectoraddtarget

Swift Customized UIButton unrecognized selector sent to instance


As the title says, I got this error message:

libc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[{Project}.{UIView} tapAction:]: unrecognized selector sent to instance 0x156406c70'
terminating with uncaught exception of type NSException

When I was trying to customize a UIButton like this:

class BaseButton: UIButton {
    
    private var action: ((UIButton)->())?

    public func tapInside(target: Any?, action: ((UIButton)->())?) {
        self.action = action
        self.addTarget(target, action: #selector(tapAction(_:)), for: .touchUpInside)
    }

    @objc private func tapAction(_ sender: UIButton) {
        if let _f = action {
            _f(self)
        }
    }
    
}

I understand that I was trying something advanced without understanding the basics.

Please let me know if there is any other solution that I don't have to create a tapAction every time.

Update: Details added to error message.


Solution

  • If you'd share the FULL error message, you should have:

    -[TheClass tapAction:] unrecognized selector sent to instance
    

    Where TheClass should be the class of the instance that called tapInside(target:action:).

    That's what might give you a tip on your issue.

    Ie, TheClass is calling on itself the method tapAction(_:), which is doesn't' know. It's like writing theClass.tapAction(someSender), this shouldn't compile, right?

    The issue, is that in addTarget(_:action:for:), the target is the one that implement the action (selector). In this case, it's self, the BaseButton instance.

    So:

    self.addTarget(target, action: #selector(tapAction(_:)), for: .touchUpInside)
    

    =>

    self.addTarget(self, action: #selector(tapAction(_:)), for: .touchUpInside)
    

    Now, since you don't need anymore the target parameter, you can remove it from the method:

    public func tapInside(target: Any?, action: ((UIButton)->())?) {...}
    

    =>

    public func tapInside(action: ((UIButton)->())?) {...}