4

Ready to use example to test in Playgrounds:

import Foundation

class Demo {

    let selector = #selector(someFunc(_:))

    func someFunc(_ word: String) {
        // Do something
    }

    func someFunc(_ number: Int) {
        // Do something
    }

}

I'm getting an Ambiguous use of 'someFunc' error.

I have tried this answer and getting something like:

let selector = #selector(someFunc(_:) as (String) -> Void)

But still getting the same result.

Any hints on how to solve this?

Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
Javier Cadiz
  • 12,326
  • 11
  • 55
  • 76
  • You could remove the `_`, so it's `someFunc(word: String)` and put `#selector(someFunc(word:))` – LinusGeffarth Oct 02 '17 at 14:49
  • The problem is that selectors are obj-c feature and obj-c won't be able to distinguish the method based on type. The selector is essentially just string `"someFunc:"`. The `#selector` syntax is only a compile-time validation. – Sulthan Oct 02 '17 at 14:49
  • You need to expose the methods to Obj-C (by using `@objc`) in order to use `#selector` with them, at which point the compiler will point out the next problem, which, as Sulthan says, is that they both have identical selectors. You'll need to give one of them a different selector, either by changing the signature, or providing a custom Obj-C name for it. – Hamish Oct 02 '17 at 14:54

2 Answers2

2

Short answer: it can't be done.

Long explanation: when you want to use a #selector, the methods need to be exposed to Objective-C, so your code becomes:

@objc func someFunc(_ word: String) {
    // Do something
}

@objc func someFunc(_ number: Int) {
    // Do something
}

Thanks to the @objc annotation, they are now exposed to Objective-C and an compatible thunk is generated. Objective-C can use it to call the Swift methods.

In Objective-C we don't call a method directly but instead we try to send a message using objc_msgSend: the compiler is not able to understand that those method are different, since the generated signature is the same, so it won't compile. You will face the error:

Method 'someFunc' with Objective-C selector 'someFunc:' conflicts with previous declaration with the same Objective-C selector.

The only way to fix it is to have different signatures, changing one or both of them.

Marco Pace
  • 3,820
  • 19
  • 38
  • 1
    `@objc` doesn't imply message dispatch; that's `dynamic` you're thinking of. `@objc` merely generates an Obj-C compatible thunk that Obj-C can then use to call into the Swift method. Swift will still use table dispatch to call the method (not message dispatch by default), or in some cases static dispatch, such as with `private` or `final` methods. – Hamish Oct 02 '17 at 15:29
  • Thanks for the reply, probably the answer is not clear enough. Tell me if I'm wrong: 1) objc generates objective-c compatible thunk, that can be used as an entry point through Swift methods. They are called using objc_msgSend, and that's where there is a problem with the question's code (that I was trying to answer to). 2) Once we are "inside" Swift, it will call methods using inline, static, virtual or dynamic dispatch: the chosen one is always the fastest one. With dynamic, we are only forcing Swift to always use the fourth option. I tried to answer to 1), not 2). Did I miss something? :) – Marco Pace Oct 02 '17 at 15:49
  • @MarcoPace AFAIK Swift won't use message dispatch unless a method is *specifically* marked `dynamic`; but you're completely correct otherwise. I just think you should change the wording of "*the compiler will not call a method directly but instead it will try to send a message using `objc_msgSend`*", because that is not true for the Swift compiler (again, unless `dynamic`). It's true for Obj-C tho. – Hamish Oct 02 '17 at 15:51
1

The selector is obviously ambiguous, neither methods have external parameter names. Remove the empty external parameters to solve this:

@objc func someFunc(word: String) {
    // Do something
}

@objc func someFunc(number: Int) {
    // Do something
}

After that, you should specify a selector with the parameter name:

#selector(someFunc(word:))

or

#selector(someFunc(number:))
Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223