web-dev-qa-db-ja.com

「@objc」以外のメソッドは、「@ objc」プロトコルのオプション要件を満たしていません

概要:

  • 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 {

}
85
user1046037

私はあなたの質問に答えることができると思いますが、それはあなたが好む答えではありません。

TL; DR:@objc関数は、現在プロトコル拡張に含まれていない可能性があります。代わりに基本クラスを作成できますが、これは理想的なソリューションではありません。

プロトコル拡張とObjective-C

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

@objcを追加すると、エラーメッセージに「@objcはクラスのメンバー、@ objcプロトコル、およびクラスの具体的な拡張機能でのみ使用できる」と表示されることもわかります。これはクラスではありません。 @objcプロトコルへの拡張は、プロトコル定義自体にある(つまり要件内にある)と同じではなく、「コンクリート」という言葉は、プロトコル拡張が具体的なクラス拡張としてカウントされないことを示唆しています。

Workaround

残念ながら、これにより、Objective-Cフレームワークでデフォルトの実装を表示する必要がある場合、プロトコル拡張機能を使用できなくなります。最初は、Swiftコンパイラが準拠する型がクラスであることを保証できなかったため、@objcがプロトコル拡張で許可されていないと考えました(UIViewControllerを明示的に指定した場合でも) 。そこで、class要件をP1に設定しました。これは機能しませんでした。

おそらく唯一の回避策は、ここでプロトコルの代わりに基本クラスを使用することですが、クラスは単一の基本クラスのみを持ち、複数のプロトコルに準拠するため、これは明らかに完全に理想的ではありません。

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

問題の報告

これはSwiftオープンソースプロジェクトで作業している人々の間ですでに議論されていると思いますが、 AppleのBug Reporter を使用することで確実に認識できます。 Swiftコアチームへの道、または Swiftのバグレポーター 。ただし、これらのどちらでも、バグが広すぎるか、既知であることがわかります。 Swiftチームは、あなたが探しているものを新しい言語機能であると考えるかもしれません。その場合、最初に メーリングリスト をチェックアウトする必要があります。

更新

2016年12月、この問題 報告された Swiftコミュニティに。この問題は、中程度の優先度で未解決としてマークされていますが、次のコメントが追加されました。

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

ただし、プロトコルは拡張機能と同じモジュールにあるため、将来のバージョンのSwiftでこれを行うことができる可能性があります。

更新2

2017年2月、この問題 公式にクローズされました Swiftコアチームメンバーの1人による「Wo n't Do」として、次のメッセージが表示されます。

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

NSObjectまたはUIViewControllerを拡張しても、望みどおりにはなりませんが、残念ながら可能になるようには見えません。

(非常に)長期的には、@objcメソッドへの依存を完全に排除できる可能性がありますが、Cocoaフレームワークは現在Swiftで記述されていないため、その時間はすぐには来ないでしょう(そして、安定したABIになるまではできません)。

160
Matthew Seaman