개요 :
- Objective-C 옵션 기능 중 하나의 기본 구현을 제공하는 프로토콜 P1이 있습니다.
- 선택적 기능의 기본 구현을 제공하면 경고가 있습니다.
컴파일러 경고 :
Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'
버전:
- 스위프트 : 3
- Xcode : 8 (공개 릴리스)
시도한 횟수 :
- 추가를 시도
@objc
했지만 도움이되지 않음
질문:
- 이 문제를 어떻게 해결합니까?
- 해결 방법이 있습니까?
암호:
@objc protocol P1 : UIAdaptivePresentationControllerDelegate {
}
extension P1 where Self : UIViewController {
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return UIViewController()
}
}
class A : UIViewController, P1 {
}
답변
나는 당신의 질문에 대답 할 수 있다고 생각하지만 당신이 좋아할 대답은 아닙니다.
요약 : @objc
기능은 현재 프로토콜 확장에 없을 수 있습니다. 이상적인 솔루션은 아니지만 대신 기본 클래스를 만들 수 있습니다.
프로토콜 확장 및 Objective-C
첫째,이 질문 / 답변 ( Can Swift Method Defined on Extensions on Extensions on Protocols Accessed in Objective-c )은 프로토콜 확장이 내부적으로 전달되는 방식 때문에 프로토콜 확장에서 선언 된 메서드가 objc_msgSend()
함수에 표시되지 않음을 시사하는 것 같습니다. 따라서 Objective-C 코드에는 표시되지 않습니다. 확장 프로그램에서 정의하려는 방법은 Objective-C에서 볼 수 있어야하기 때문에 ( UIKit
사용할 수 있으므로)를 포함하지 않은 것에 대해 소리를 지르지 @objc
만 일단 포함하면 @objc
허용되지 않기 때문에 소리를 지 릅니다 . 프로토콜 확장. 이는 프로토콜 확장이 현재 Objective-C에 표시되지 않기 때문일 수 있습니다.
@objc
“@objc는 클래스의 멤버, @objc 프로토콜 및 클래스의 구체적인 확장에만 사용할 수 있습니다.”라는 상태 를 추가하면 오류 메시지가 표시 됩니다. 이것은 수업이 아닙니다. @objc 프로토콜에 대한 확장은 프로토콜 정의 자체 (예 : 요구 사항)에있는 것과 동일하지 않으며 “concrete”라는 단어는 프로토콜 확장이 구체적인 클래스 확장으로 간주되지 않음을 암시합니다.
해결 방법
불행히도 이것은 기본 구현이 Objective-C 프레임 워크에 표시되어야 할 때 프로토콜 확장을 사용하는 것을 거의 완전히 방지합니다. 처음 @objc
에는 Swift Compiler가 형식을 준수하는 클래스가 클래스라는 것을 보장 할 수 없기 때문에 프로토콜 확장에서 허용되지 않는다고 생각했습니다 UIViewController
. 그래서 내가 넣어 class
에 요구 사항을 P1
. 이것은 작동하지 않았습니다.
아마도 유일한 해결 방법은 여기에서 프로토콜 대신 기본 클래스를 사용하는 것입니다.하지만 클래스가 단일 기본 클래스 만 가질 수 있지만 여러 프로토콜을 준수 할 수 있기 때문에 이것은 분명히 완전히 이상적이지는 않습니다.
이 경로를 선택하는 경우이 질문 ( Swift 3 ObjC Optional Protocol Method Not Called in Subclass )을 고려하십시오. Swift 3의 또 다른 현재 문제는 하위 클래스가 수퍼 클래스의 선택적 프로토콜 요구 사항 구현을 자동으로 상속하지 않는다는 것입니다. 그 질문에 대한 대답 @objc
은 그것을 우회하기 위해 특별한 적응을 사용 합니다.
문제보고
Swift 오픈 소스 프로젝트에서 일하는 사람들 사이에서 이미 논의되고 있다고 생각하지만 , 결국 Swift Core Team으로 갈 가능성이있는 Apple의 Bug Reporter 또는 Swift의 버그 리포터 를 사용하여 알고 있는지 확인할 수 있습니다 . 그러나 이들 중 하나는 버그가 너무 광범위하거나 이미 알려져 있음을 알 수 있습니다. Swift 팀은 당신이 찾고있는 것을 새로운 언어 기능으로 고려할 수도 있습니다.이 경우 먼저 메일 링리스트를 확인해야 합니다 .
최신 정보
2016 년 12 월이 문제 는 Swift 커뮤니티 에보고 되었습니다. 이 문제는 여전히 중간 우선 순위로 진행 중으로 표시되지만 다음과 같은 댓글이 추가되었습니다.
이것은 의도 된 것입니다. 프로토콜 준수 후에 확장이 추가 될 수 있기 때문에 모든 채택 자에게 메소드 구현을 추가 할 방법이 없습니다. 하지만 확장이 프로토콜과 동일한 모듈에 있으면 허용 할 수 있다고 생각합니다.
그러나 프로토콜이 확장과 동일한 모듈에 있기 때문에 향후 Swift 버전에서이 작업을 수행 할 수 있습니다.
업데이트 2
2017 년 2 월,이 문제 는 다음 메시지와 함께 Swift Core Team 멤버 중 한 명이 “Wo n’t Do” 로 공식적으로 종결 되었습니다.
이는 의도적입니다. 프로토콜 확장은 Objective-C 런타임의 제한으로 인해 @objc 진입 점을 도입 할 수 없습니다. @objc 진입 점을 NSObject에 추가하려면 NSObject를 확장합니다.
확장 NSObject
하거나 심지어 UIViewController
원하는 것을 정확하게 달성하지 못하지만 불행히도 가능해 보이지는 않습니다.
(매우) 장기적인 미래에 우리는 @objc
메소드에 대한 의존도를 완전히 없앨 수 있을지 모르지만 Cocoa 프레임 워크가 현재 Swift로 작성되지 않았기 때문에 조만간 오지 않을 것입니다 (안정적인 ABI를 갖기 전까지는 불가능합니다). .
업데이트 3
2019 년 가을부터 점점 더 많은 Apple 프레임 워크가 Swift로 작성되고 있기 때문에 이것은 문제가되지 않습니다. 예를 들어, SwiftUI
대신 을 사용 하면 메서드를 참조 할 때 필요하지 UIKit
않으므로 문제를 완전히 피할 @objc
수 있습니다 SwiftUI
.
Swift로 작성된 Apple 프레임 워크는 다음과 같습니다.
- SwiftUI
- RealityKit
- 결합시키다
- CryptoKit
Swift가 공식적으로 Swift 5.0 및 5.1에서 각각 ABI 및 모듈 안정이므로이 패턴이 시간이 지남에 따라 계속 될 것으로 예상 할 수 있습니다.
답변
내가 사용하는 신속한 프레임 워크에서 ‘모듈 안정성'( ‘배포 용 라이브러리 빌드’설정)을 활성화 한 후이 문제를 만났습니다.
내가 가진 것은 다음과 같습니다.
class AwesomeClass: LessAwesomeClass {
...
}
extension AwesomeClass: GreatDelegate {
func niceDelegateFunc() {
}
}
확장 기능에 다음 오류가 있습니다.
-
‘LessAwesomeClass’하위 클래스 확장의 ‘@objc’인스턴스 메서드에는 iOS 13.0.0이 필요합니다.
-
‘@objc’가 아닌 메서드 ‘niceDelegateFunc’는 ‘@objc’프로토콜 ‘GreatDelegate’의 요구 사항을 충족하지 않습니다.
확장이 아닌 클래스로 함수를 이동하면 문제가 해결되었습니다.
답변
또 다른 해결 방법이 있습니다. 이 문제도 발생했으며 아직 UIKit에서 SwiftUI로 전환 할 수 없습니다. 기본 구현을 공통 기본 클래스로 이동하는 것은 나에게도 옵션이 아닙니다. 내 기본 구현은 상당히 광범위했기 때문에 모든 코드를 복제하고 싶지 않았습니다. 내가 사용한 해결 방법은 프로토콜에서 래퍼 함수를 사용한 다음 각 클래스에서 해당 함수를 호출하는 것입니다. 예쁘지는 않지만 상황에 따라 대안보다 나을 수 있습니다. 코드는 다음과 같습니다.
@objc protocol P1 : UIAdaptivePresentationControllerDelegate {
}
extension P1 where Self : UIViewController {
func wrapPresentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return UIViewController()
}
}
class A : UIViewController, P1 {
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return wrapPresentationController(controller, viewControllerForAdaptivePresentationStyle: style)
}
}