programing tip

Swift #selector 구문으로 "모호한 사용"컴파일 오류를 해결하려면 어떻게해야합니까?

itbloger 2020. 11. 2. 07:41
반응형

Swift #selector 구문으로 "모호한 사용"컴파일 오류를 해결하려면 어떻게해야합니까?


[ 참고이 질문은 원래 Swift 2.2에서 공식화되었습니다. 두 가지 중요한 언어 변경을 포함하여 Swift 4에서 수정되었습니다. 첫 번째 메소드 매개 변수 외부는 더 이상 자동으로 억제되지 않으며 선택자는 Objective-C에 명시 적으로 노출되어야합니다.]

내 수업에 다음 두 가지 메서드가 있다고 가정 해 보겠습니다.

@objc func test() {}
@objc func test(_ sender:AnyObject?) {}

이제 Swift 2.2의 새로운 #selector구문을 사용하여 첫 번째 메소드 인 func test(). 어떻게하나요? 내가 이것을 시도 할 때 :

let selector = #selector(test) // error

... "의 모호한 사용"오류가 표시 test()됩니다. 하지만 이렇게 말하면 :

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

... 오류가 도망 간다, 그러나 나는 지금 말하는 겁니다 잘못된 방법 의 하나 매개 변수. 매개 변수가 없는 것을 참조하고 싶습니다 . 어떻게하나요?

[참고 : 예제는 인위적이지 않습니다. NSObject에는 Objective-C copycopy:인스턴스 메서드 인 Swift copy()copy(sender:AnyObject?); 실생활에서 쉽게 문제가 발생할 수 있습니다.]


[ 참고이 답변은 원래 Swift 2.2에서 공식화되었습니다. 두 가지 중요한 언어 변경을 포함하여 Swift 4에서 수정되었습니다. 첫 번째 메소드 매개 변수 외부는 더 이상 자동으로 억제되지 않으며 선택자는 Objective-C에 명시 적으로 노출되어야합니다.]

함수 참조를 올바른 메서드 서명 으로 캐스팅 하여이 문제를 해결할 수 있습니다 .

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

(하지만 제 생각에는 이렇게 할 필요가 없습니다. 저는이 상황을 버그로 간주하여 함수를 참조하는 Swift의 구문이 부적절하다는 것을 보여줍니다. 버그 보고서를 제출했지만 소용이 없습니다.)


#selector구문 을 요약하면 다음 과 같습니다.

이 구문의 목적은 선택자를 리터럴 문자열로 제공 할 때 발생할 수있는 너무 흔한 런타임 충돌 (일반적으로 "인식되지 않은 선택자")을 방지하는 것입니다. 함수 참조를#selector() 취하고 컴파일러는 함수가 실제로 존재하는지 확인하고 Objective-C 선택기에 대한 참조를 해결합니다. 따라서 쉽게 실수를 할 수 없습니다.

( 편집 : 예, 할 수 있습니다. 완전한 lunkhead가 될 수 있으며에서 지정한 작업 메시지를 구현하지 않는 인스턴스로 대상을 설정할 수 있습니다 #selector. 컴파일러는 당신을 멈추지 않을 것이고 당신은 좋은 옛날. 한숨 ...)

함수 참조는 다음 세 가지 형식 중 하나로 나타날 수 있습니다.

  • 베어 이름 함수의. 함수가 모호하지 않으면 충분합니다. 따라서 예를 들면 다음과 같습니다.

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

    test메서드 는 하나뿐 이므로 #selector매개 변수를 사용하고 #selector매개 변수를 언급하지 않더라도 참조합니다. 배후에서 해결 된 Objective-C 선택기는 여전히 올바르게 "test:"(콜론을 사용하여 매개 변수를 나타냄) 그대로입니다.

  • 나머지 시그니처 와 함께 함수의 이름 . 예를 들면 :

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

    두 가지 test방법이 있으므로 차별화해야합니다. 표기법 은 매개 변수 test(_:)가있는 두 번째 표기법으로 해석됩니다 .

  • 나머지 서명이 있거나없는 함수의 이름과 매개 변수 유형 을 표시 하는 캐스트 . 그러므로:

    @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)
    }
    

    여기서 우리는 한 오버로드 test(_:) . 오브젝티브 C는 오버로드를 허용하지 않기 때문에 과부하 때문에 단지 그들 중 하나가 노출되어, 오브젝티브 C에 노출 될 수 없으며, 우리는 단지 하나에 대한 선택 형성 할 수 있다 셀렉터는 오브젝티브 C의 기능이기 때문에, 노출을 . 그러나 우리는 스위프트에 관한 한 여전히 명확하게 해야합니다 .

    (내 의견으로는 오용되는 것은 위의 답변의 기초로 사용되는 언어 적 기능입니다.)

또한 함수가 어떤 클래스에 있는지 알려줌으로써 Swift가 함수 참조를 해결하도록 도와야 할 수도 있습니다.

  • 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 {
        @objc 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.)

참고URL : https://stackoverflow.com/questions/35658334/how-do-i-resolve-ambiguous-use-of-compile-error-with-swift-selector-syntax

반응형