Argument of ‘#selector’ refers to instance method ‘buttonTapped()’ that is not exposed to Objective-C WHY SWIFT WHY

A common error in Swift

Image for post
Image for post
Image: Ryanbaker271

Difficulty: Beginner | Easy | Normal | Challenging (although the in-depth explanations are quite tricky, they can be skipped)

When you write Swift code that needs to be called from Objective-C you need to expose that code to Objective-C, and to do this we can prefix a function with @objc attribute.

The real-life example

We can set up a UITapGestureRecognizer and then add it to a UIButton (called UIButton here):

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(buttonTapped))
myButton.addGestureRecognizer(tapGesture)

Now the #selector is the clue that we need to expose that function to Objective-C.

The simple solution to this is to prefix a function with @objc to make it available, that is make an Objective-C thunk.

To break this down; when you mark a function @objc that creates the appropriate Objective-C selector and name that can be called by the Objective-C runtime.

Such a function might be

func buttonTapped() {
// perform function when the button is tapped
}

which if we implement as-is will give us a rather worrying error

Image for post
Image for post

which can be solved with the following function featuring the @objc attribute

@objc func buttonTapped() {
// perform function when the button is tapped
}

the error goes away!

In depth

Adding @objc makes a function available to the Objective-C runtime framework. When the @objc attribute is used

@objc func buttonTapped()

overrides any existing Objective-C method

- (void)buttonTapped

if one exists in the superclass and therefore calls the Swift function each time.

And so the problem is solved

  • protocols marked with @objc can’t inherit from protocols that aren’t marked with the attribute
  • enums marked with @objc are exposed to Objective-C as a concatenation of the enumeration name and the case name
  • Applying @objc unnecessarily increases files sizes and degrades performance

Conclusion:

Using attributes isn’t all that tricky in Swift, but it helps to know why we need to add an @objc attribute to our functions rather than being in the situation where it feels the only option available is to copy and paste code from stackoverflow.

This article has proposed a solution for the Argument of ‘#selector’ refers to instance method ‘buttonTapped()’ that is not exposed to Objective-C error, and explained why it makes sense.

Swift away!

Extend your knowledge

The @objc attribute is defined in Apple’s documentation (HERE)

The Twitter contact:

Any questions? You can get in touch with me here

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store