1. ホーム
  2. swift

[解決済み] 非'@objc'メソッドは'@objc'プロトコルのオプション要件を満たしていない

2022-08-29 03:54:26

質問

概要

  • Objective-Cのオプション関数の1つのデフォルトの実装を提供するプロトコル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 {

}

どのように解決するのですか?

あなたの質問に答えることができると思いますが、あなたが気に入るような答えではありません。

TL;DRです。 @objc 関数は現在プロトコル拡張に含まれていないかもしれません。代わりに基底クラスを作成することもできますが、それは理想的な解決策ではありません。

プロトコル拡張と Objective-C

まず、この質問/回答( Objective-cでアクセスされるプロトコル上の拡張機能で定義されたSwiftメソッドは可能か? ) は、プロトコル拡張がフードの下でディスパッチされる方法のために、プロトコル拡張で宣言されたメソッドが objc_msgSend() 関数には表示されず、したがって Objective-C コードからは見えません。拡張機能で定義しようとしているメソッドは Objective-C から見える必要があるので (つまり UIKit が使用できるように) Objective-C から見える必要があるため、拡張機能で定義しようとしているメソッドに @objc を含まないことに対して怒鳴りますが、 含めた後は @objc はプロトコル拡張では許可されないからです。これはおそらく、プロトコル拡張は現在 Objective-C からは見ることができないからでしょう。

また、一度エラーメッセージに @objc は "@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes." これはクラスではありません。@objc プロトコルの拡張はプロトコル定義自体(つまり要件)にあるのと同じではなく、また "concrete" という言葉はプロトコル拡張が具象クラス拡張としてカウントされないことを示していると思われます。

回避策

残念ながら、デフォルトの実装が Objective-C フレームワークから見える必要がある場合、これはプロトコル拡張の使用をかなり完全に妨げます。最初、私はおそらく @objc がプロトコル拡張子で許可されていないのは、Swift コンパイラが適合する型がクラスであることを保証できないからではないかと考えました (たとえあなたが具体的に UIViewController ). そこで、私は class の要件を P1 . これはうまくいきませんでした。

おそらく唯一の回避策は、ここでプロトコルの代わりに単純にベースクラスを使用することですが、クラスが単一のベースクラスしか持っていなくても複数のプロトコルに適合することがあるため、これは明らかに完全に理想的なものではありません。

このルートを選択した場合、この質問( Swift 3 ObjC オプションのプロトコルメソッドがサブクラスで呼び出されない ) を考慮してください。Swift 3 の別の現在の問題は、サブクラスが自動的にそれらのスーパークラスのオプションのプロトコル要件の実装を継承しないことであると思われます。その質問に対する答えは、特別に適応された @objc の特別な適応を使用して、それを回避します。

問題を報告する

この件は、Swift のオープンソースプロジェクトで作業している人たちの間ですでに議論されていると思いますが、彼らが認識していることを確認するために Apple のバグ リポーター を使用するか、最終的に Swift コア チームに届くと思われる Swift のバグ報告者 . これらのいずれかが、あなたのバグが広すぎるか、すでに知られていることを見つけるかもしれません。Swift チームは、あなたが探しているものが新しい言語機能であるとみなすかもしれません。 メーリングリスト .

更新情報

2016年12月に、この問題 が報告されました をSwiftコミュニティに提出しました。この問題はまだ優先度「中」でオープンとなっていますが、以下のコメントが追加されています。

これは意図的なものです。拡張はプロトコルへの適合後に追加される可能性があるので、すべての採用者にメソッドの実装を追加する方法はありません。拡張機能がプロトコルと同じモジュールにあれば許可できるのでしょうけど。

プロトコルが拡張機能と同じモジュールにあるので、しかし、Swiftの将来のバージョンでこれを行うことができるかもしれません。

アップデート2

2017年2月、この問題 は正式に終了しました as "Won't Do"として、Swift Core Teamのメンバーの一人が次のようなメッセージを残しています。

これは意図的なものです。Objective-C ランタイムの制限により、プロトコル拡張は @objc エントリポイントを導入することができません。NSObject に @objc エントリ ポイントを追加したい場合は、NSObject を拡張してください。

拡張する NSObject あるいは UIViewController は、まさにあなたが望むものを達成することはできませんが、残念ながら可能になるとは思えません。

(非常に) 長期的な将来では、私たちは @objc メソッドへの依存を完全になくすことができるかもしれませんが、Cocoa フレームワークは現在 Swift で書かれていないため (そして Swift が安定した ABI を持つまでそうできない)、その時はおそらくすぐには来ないでしょう。

アップデート 3

2019年秋現在、AppleのフレームワークがSwiftで書かれることが多くなってきているため、この問題は少なくなってきています。例えば SwiftUI の代わりに UIKit を使用すると、問題を完全に回避できます。 @objc は決して必要ないからです。 SwiftUI メソッドを参照するときには決して必要ありません。

Swiftで書かれたAppleのフレームワークには

  • SwiftUI
  • リアリティキット
  • 組み合わせる
  • 暗号化キット

Swift が Swift 5.0 と 5.1 の時点でそれぞれ公式に ABI とモジュールが安定しているので、このパターンは時間とともに継続すると予想されます。