プロトコル拡張で定義されたメソッドをSwift from Objective-Cから呼び出すことは可能ですか?
例えば:
protocol Product {
var price:Int { get }
var priceString:String { get }
}
extension Product {
var priceString:String {
get {
return "$\(price)"
}
}
}
class IceCream : Product {
var price:Int {
get {
return 2
}
}
}
IceCream
のインスタンスの価格文字列は '$ 2'であり、Swiftでアクセスできますが、このメソッドはObjective-Cでは表示されません。コンパイラはエラーをスローします 'IceCream'の表示された@interfaceはセレクタを宣言しません... '。
私の構成では、メソッドがSwiftオブジェクトの実装で直接定義されている場合、すべてが期待どおりに機能します。つまり、次のようになります。
protocol Product {
var price:Int { get }
var priceString:String { get }
}
class IceCream : Product {
var price:Int {
get {
return 2
}
}
var priceString:String {
get {
return "$\(price)"
}
}
}
私はこれに対する答えが「いいえ」であるとほぼ確信していますが、公式のAppleそれを説明する文書は見つかりませんでした。
これは、すべてのメソッド呼び出しに動的ディスパッチを使用する提案について説明しているSwift-evolutionメーリングリストからのメッセージです。これにより、Objective-Cのような呼び出しセマンティクスが提供されます。
繰り返しますが、これに対する唯一の例外はプロトコル拡張です。言語の他の構造とは異なり、プロトコル拡張メソッドは、仮想ディスパッチによって異なる結果が生じる状況で静的にディスパッチされます。この不一致を防ぐコンパイラエラーはありません。 ( https://lists.Swift.org/pipermail/Swift-evolution/Week-of-Mon-20151207/001707.html )
プロトコル拡張はSwiftのみの言語機能であるため、objc_msgSend()
には表示されません。
プロトコルからpriceString
を削除しても問題がなく、拡張機能にのみ含まれている場合は、ヘルパーでIceCream
をProduct
にキャストすることでプロトコル拡張機能を呼び出すことができます。拡張。
@objc protocol Product {
var price:Int { get }
}
extension Product {
var priceString:String {
return "$\(price)"
}
}
// This is the trick
// Helper extension to be able to call protocol extension from obj-c
extension IceCream : Product {
var priceString:String {
return (self as Product).priceString
}
}
@objc class IceCream: NSObject {
var price: Int {
return 2
}
}
プロトコル拡張は@objcプロトコルでは機能しませんが、回避策としてSwiftでクラスを拡張できます。
@objc protocol Product {
var price: NSNumber? { get }
var priceString:String { get }
}
...
// IceCream defined in Objective-C that does not extend Product
// but has @property(nonatomic, strong, nullable) (NSNumber*)price
// to make it confirm to Product
...
extension IceCream: Product {
var priceString:String {
get {
return "$\(price ?? "")"
}
}
}
このコードはまったくクリーンではありませんが、機能します。