[swift] Swift 4에서 #selector ()를 사용하여 @objc 추론 폐기를 처리하는 방법은 무엇입니까?

프로젝트의 소스 코드를 Swift 3에서 Swift 4로 변환하려고합니다. Xcode가 알려주는 경고 중 하나는 선택기에 관한 것입니다.

예를 들어 다음과 같이 일반 선택기를 사용하여 버튼에 대상을 추가합니다.

button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)

이것이 나타내는 경고입니다.

‘#selector’의 인수는 Swift 4에서 사용되지 않는 ‘@objc’속성 유추에 의존하는 ‘ViewController’의 인스턴스 메소드 ‘myAction ()’을 나타냅니다.

이 인스턴스 메소드를 Objective-C에 노출 시키려면 ‘@objc’를 추가하십시오.

이제 Fix오류 메시지를 누르면 내 기능이 수행됩니다.

// before
func myAction() { /* ... */ }

// after
@objc func myAction() { /* ... */ }

@objc마크 를 포함하기 위해 모든 기능의 이름을 바꾸고 싶지 않으며 필요하지 않다고 가정합니다.

지원 중단을 처리하기 위해 선택기를 다시 작성하려면 어떻게해야하나요?


관련 질문 :



답변

해결 방법은 정확합니다. Objective-C에 노출되는 방법을 만들기 위해 선택할 수있는 선택기에 대해 아무것도 없습니다.

이 경고의 첫 번째 이유는 SE-0160 의 결과입니다 . Swift 4 이전에는 상속 클래스 internal의 Objective-C 호환 상위 멤버 가 Objective-C에 노출 된 NSObject것으로 추론 @objc되었으므로 선택기를 사용하여 호출 할 수있었습니다 (Obj-C 런타임이 메소드를 검색하기 위해 필요하므로) 주어진 선택기에 대한 구현).

그러나 Swift 4에서는 더 이상 그렇지 않습니다. @objc예를 들어, @objc메소드의 오버라이드 , @objc프로토콜 요구 사항의 구현 및와 @objc같은 속성을 갖는 선언과 같이 매우 구체적인 선언 만이 유추 됩니다 @IBOutlet.

위의 링크 된 제안에 자세히 설명 된 바와 같이 이것의 배후의 동기 는 우선 NSObject동일한 선택기가 있기 때문에 상속 클래스의 메서드 오버로드가 서로 충돌 하는 것을 방지하는 것입니다 . 둘째, Obj-C에 노출 될 필요가없는 멤버에 대해 썽크를 생성하지 않아도되므로 이진 크기를 줄이고 세 번째로 동적 연결 속도를 향상시킵니다.

멤버를 Obj-C에 노출하려면 @objc예를 들어 다음 과 같이 표시해야합니다 .

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button.addTarget(self, action: #selector(foo), for: .touchUpInside)
    }

    @objc func foo() {
       // ...
    }
}

( “최소 추론”옵션을 선택한 상태로 실행할 때 선택기가있는 경우 마이그레이션 기는이 작업을 자동으로 수행해야합니다)

멤버 그룹을 Obj-C에 노출 시키려면 다음을 사용하십시오 @objc extension.

@objc extension ViewController {

    // both exposed to Obj-C
    func foo() {}
    func bar() {}
}

이렇게하면 정의 된 모든 멤버가 Obj-C에 노출되고 Obj-C에 노출 될 수없는 멤버 (에 명시 적으로 표시되지 않은 경우 @nonobjc)에 오류가 발생합니다.

모든 Obj-C 호환 멤버를 Obj-C에 노출 해야하는 클래스가있는 경우 클래스를 @objcMembers다음 과 같이 표시 할 수 있습니다 .

@objcMembers
class ViewController: UIViewController {
   // ...
}

이제 추론 할 수있는 모든 구성원이됩니다 @objc. 그러나 위에서 언급 한 단점을 불필요하게 노출시키는 단점을 감안할 때 Obj-C에 노출 된 모든 구성원 이 실제로 필요한 경우가 아니면이 작업을 수행하지 않는 것이 좋습니다 .


답변

애플 공식 문서 . @objc를 사용하여 Selector 메서드를 호출해야합니다.

Objective-C에서 선택기는 Objective-C 메소드의 이름을 나타내는 유형입니다. Swift에서 Objective-C 선택기는 Selector구조 로 표시되며 #selector
표현식을 사용하여 구성 할 수 있습니다 . Objective-C에서 호출 할 수있는 메소드의 선택기를 작성하려면 다음과 같이 메소드 이름을 전달하십시오
#selector(MyViewController.tappedButton(sender:)). 특성의 목표-C 게터 세터 또는 방법에 대한 선택을 구성하기 위해, 접두어 속성 이름 통과 getter:또는 setter:같은 라벨,
#selector(getter: MyViewController.myButton).


답변

현재 Swift 4.2에서는 @IBAction을 메소드에 할당하는 것만 으로이 어리석은 @objc 주석을 피할 수 있다고 생각합니다.

“`

let tap  =  UITapGestureRecognizer(target: self, action: #selector(self.cancel))


@IBAction func cancel()
{
    self.dismiss(animated: true, completion: nil)
}


답변

다른 답변에서 이미 언급했듯이 @objc선택기 의 주석 을 피할 수있는 방법이 없습니다 .

그러나 OP에 언급 된 경고는 다음 단계를 수행하여 침묵시킬 수 있습니다.

  1. 빌드 설정으로 이동
  2. 키워드 @objc 검색
  3. Swift 3 @objc 인터페이스 의 값 을Off

아래는 위에서 언급 한 단계를 보여주는 스크린 샷입니다.

"Swift 3 @objc 인터페이스"경고음

도움이 되었기를 바랍니다


답변

뷰 컨트롤러에 객관적인 c 멤버가 필요한 경우 뷰 컨트롤러 상단에 @objcMembers 를 추가하십시오 . 그리고 코드에 IBAction을 추가하여이를 피할 수 있습니다.

@IBAction func buttonAction() {

}

스토리 보드에서이 콘센트를 연결하십시오.


답변