web-dev-qa-db-ja.com

@objcキーワード拡張サブクラスの動作

誰かが理由を説明できますか@objcキーワードは、コードをコンパイルするためにここで必要ですか?

私が理解したように、このキーワードは、ObjCメッセージメソッドのディスパッチを機能させるために使用されます。ただし、これはNSObjectインスタンスではありません。

 class MyClass {
 }

 extension MyClass {
     @objc func extensionMethod() { /// THIS LINE
         print("A")
     }
 }

 class SubClass: MyClass {
     override func extensionMethod() {
         print("B")
     }
 }

@objcキーワードはメッセージディスパッチとdynamicを有効にしますか?か否か?

12
Vyacheslav

@objcキーワードはdynamicと同様にメッセージディスパッチを有効にしますか?

通常ではありません。通常、@objc属性は、それ自体で特定のクラスメンバーをObjective-Cに公開するだけです。Swiftは、テーブルまたは静的ディスパッチを使用して、自由にディスパッチできます。 Swiftが呼び出すときにメッセージディスパッチを使用する場合は、メンバーをdynamicとしてマークする必要があります。

ただし、非最終的な@objcクラスextensionメンバーの場合、Swiftは自動的にdynamicであると推測します。どうして?相互運用性の理由から、Swiftでは、@objc拡張メンバーをオーバーライドおよびオーバーライドできます(サブクラスカテゴリのObj-Cメソッドをオーバーライドする方法と同様)。この動作を実現するために、SwiftはObj-Cメッセージディスパッチに依存しています。

したがって、拡張機能では、@objcdynamicを推測します。拡張メンバーは現在Swiftクラスのvtableに追加できないため(Swift vtableには現在メンバーを動的に追加できないため)、Obj-Cランタイムに公開せずに拡張メンバーをオーバーライドすることはできません。実行時)。

しかし、これはNSObjectインスタンスではありません。

Appleプラットフォーム(つまり、Obj-C相互運用機能を備えたプラットフォーム)では、all SwiftクラスはObj-Cランタイムに公開され、すべて暗黙的にNSObjectProtocolに準拠する_SwiftObjectと呼ばれる特別なObj-C基本クラス。したがって、Swiftクラスは、NSObjectから継承しなくても、メッセージディスパッチを利用できます。

16
Hamish