Swift wants argument of #selector to be exposed to Objective-C

I have a Swift project where I want to attach a method to a UIButton’s tap event. I have the following code:

class MyClass {
  let myButton = UIButton(frame: CGRectMake(50, 50, 100, 50))
  init() {
    myButton.addTarget(self, #selector(self.didTap(_:)), forControlEvents: .TouchUpInside)
  }

  func didTap(sender: UIButton) {
    print("Tapped")
  }
}

XCode highlights my addTarget line and says:

  • Calling C++ function from objective C class
  • Apple MDM push error, but only to some iOS devices
  • How to filter Quickblox users?
  • FirebaseStorage: How to Delete Directory
  • How to use delegates to communicate data from a custom cell to a label in the parent view
  • UINavigationBar custom transition animation
  • Argument of '#selector' refers to a method that is not exposed to Objective-C
    

    If I add the @objc prefix to my func didTap like it suggests then everything works fine.

    Do I have something enabled in my build settings which is causing this strange behaviour?

    PS. I get this behaviour in 7.3.1. But if I try this in 7.2.1 it doesn’t accept the #selector(method(_:)) syntax, and Selector("method:") works fine.

    3 Solutions Collect From Internet About “Swift wants argument of #selector to be exposed to Objective-C”

    Selectors are a feature of Objective-C and can only be used with methods that are exposed to the dynamic Obj-C runtime. You can’t have a selector to a pure Swift method.

    If your class inherits from NSObject then its public methods are exposed to Obj-C automatically. Since your class does not inherit from NSObject you have to use the @objc attribute to indicate that you want this method exposed to Obj-C so that it may be called with an Obj-C selector.

    #selector() is the new syntax in Swift 2.2. It allows the compiler to check that the selector you’re trying to use actually exists. The old syntax is deprecated and will be removed in Swift 3.0.

    If I add the @objc prefix to my func didTap like it suggests then everything works fine.

    Do I have something enabled in my build settings which is causing this strange behaviour?

    No. What you’re seeing is normal. Selectors are an Objective-C feature, and so is using a selector to send a message to your class instance. The only way Objective-C can send that message is if it can see either your class or the method itself. MyClass is not itself derived from NSObject, so Objective-C can’t see it. So if you don’t want to derive it from NSObject, you at least have to expose the method to Objective-C by marking it with @objc.

    and Selector(“method:”) works fine

    In earlier versions of Swift, the compiler would not help you in this situation, so your code would compile. But you would have crashed when the message arrived and Objective-C couldn’t find the method. The whole point of the #selector syntax is to help you avoid that crash. And that’s just what it did!

    You have to subclass from NSObject