How do I resolve “ambiguous use of” compile error with Swift #selector syntax?

Let’s say I have these two methods in my class:

func test() {}
func test(sender:AnyObject?) {}

Now I want to use Swift 2.2’s new #selector syntax to make a selector corresponding to the first of these methods, func test(). How do I do it? When I try this:

  • Using multiple UIGestureRecognizers simultaneously like UIRotationGestureRecognizer & UIPanGestureRecognizer in Swift 3
  • Swift - Converting JSON date to Swift compatible date
  • What's the difference between Struct based and Class based singletons?
  • Check network status in Swift
  • Insertion-Order Dictionary (like Java's LinkedHashMap) in Swift?
  • Convert AVAudioPCMBuffer to NSData and back
  • let selector = #selector(test) // error
    

    … I get an error, “Ambiguous use of test().” But if I say this:

    let selector = #selector(test(_:)) // ok, but...
    

    … the error goes away, but I’m now referring to the wrong method, the one with a parameter. I want to refer to the one without any parameter. How do I do it?

    [Note: the example is not artificial. NSObject has both Objective-C copy and copy: instance methods, Swift copy() and copy(sender:AnyObject?); so the problem can easily arise in real life.]

    Solutions Collect From Internet About “How do I resolve “ambiguous use of” compile error with Swift #selector syntax?”

    You can work around this problem by casting your function reference to the correct method signature:

    let selector = #selector(test as () -> Void)
    

    (However, in my opinion, you should not have to do this. I regard this situation as a bug, revealing that Swift’s syntax for referring to functions is inadequate. I filed a bug report, but to no avail.)


    Just to summarize the new #selector syntax:

    The purpose of this syntax is to prevent the all-too-common runtime crashes (typically “unrecognized selector”) that can arise when supplying a selector as a literal string. #selector() takes a function reference, and the compiler will check that the function really exists and will resolve the reference to an Objective-C selector for you. Thus, you can’t readily make any mistake.

    (EDIT: Okay, yes you can. You can be a complete lunkhead and set the target to an instance that doesn’t implement the action message specified by the #selector. The compiler won’t stop you and you’ll crash just like in the good old days. Sigh…)

    A function reference can appear in any of three forms:

    • The bare name of the function. This is sufficient if the function is unambiguous. Thus, for example:

      func test(sender:AnyObject?) {}
      func makeSelector() {
          let selector = #selector(test)
      }
      

      There is only one test method, so this #selector refers to it even though it takes a parameter and the #selector doesn’t mention the parameter. The resolved Objective-C selector, behind the scenes, will still correctly be "test:" (with the colon, indicating a parameter).

    • The name of the function along with the rest of its signature. For example:

      func test() {}
      func test(sender:AnyObject?) {}
      func makeSelector() {
          let selector = #selector(test(_:))
      }
      

      We have two test methods, so we need to differentiate; the notation test(_:) resolves to the second one, the one with a parameter.

    • The name of the function with or without the rest of its signature, plus a cast to show the types of the parameters. Thus:

      @objc func test(integer:Int) {}
      @nonobjc func test(string:String) {}
      func makeSelector() {
          let selector1 = #selector(test as (Int) -> Void)
          // or:
          let selector2 = #selector(test(_:) as (Int) -> Void)
      }
      

      Here, we have overloaded test(_:). The overloading cannot be exposed to Objective-C, because Objective-C doesn’t permit overloading, so only one of them is exposed, and we can form a selector only for the one that is exposed, because selectors are an Objective-C feature. But we must still disambiguate as far as Swift is concerned, and the cast does that.

      (It is this linguistic feature that is used — misused, in my opinion — as the basis of the answer above.)

    Also, you might have to help Swift resolve the function reference by telling it what class the function is in:

    • If the class is the same as this one, or up the superclass chain from this one, no further resolution is usually needed (as shown in the examples above); optionally, you can say self, with dot-notation (e.g. #selector(self.test), and in some situations you might have to do so.

    • Otherwise, you use either a reference to an instance for which the method is implemented, with dot-notation, as in this real-life example (self.mp is an MPMusicPlayerController):

      let pause = UIBarButtonItem(barButtonSystemItem: .Pause, 
          target: self.mp, action: #selector(self.mp.pause))
      

      …or you can use the name of the class, with dot-notation:

      class ClassA : NSObject {
          func test() {}
      }
      class ClassB {
          func makeSelector() {
              let selector = #selector(ClassA.test)
          }
      }
      

      (This seems a curious notation, because it looks like you’re saying test is a class method rather than an instance method, but it will be correctly resolved to a selector nonetheless, which is all that matters.)