5

Swift 拡張機能を使用してオーバーロードされたメソッドを Objective-C クラスに追加すると、最初のメソッドしか呼び出されないように見え、実行時に予期しない動作やクラッシュが発生します。(Objective-C ではなく) Swift クラスの拡張機能は正しく機能します。これに対する回避策があるかどうかを確認し、これがバグであることを確認し、Apple に報告する必要があることを確認したいと思います。Swift がサポートしているのに対し、Objective-C はオーバーロードされたメソッドをサポートしていないことを考えると、この 2 つを混在させると問題が発生する可能性があると想像できます。

拡張機能を取得するクラスは、init 関数を持つ Objective-C クラスを除いて、両方とも空です。ObjClass は .h および .m ファイル内で宣言され、Swift ブリッジ ヘッダーを使用してインポートされます。元の SwiftClass は、Swift 拡張機能と共にコード サンプル内で定義されています。

extension ObjClass {
    func log(param: Int32)    { NSLog("ObjClass->Int32: " + String(param)) }
    func log(param: String)   { NSLog("ObjClass->String: " + param) }
    func log(param: ObjClass) { NSLog("ObjClass->ObjClass") }
}

class SwiftClass {
}

extension SwiftClass {
    func log(param: Int32)    { NSLog("SwiftClass->Int32: " + String(param)) }
    func log(param: String)   { NSLog("SwiftClass->String: " + param) }
    func log(param: ObjClass) { NSLog("SwiftClass->ObjClass") }
}

次に、文字列、int、およびオブジェクトを使用してオーバーロードされたメソッドを呼び出します。

var objClass = ObjClass()
objClass.log(10)
objClass.log("string")
objClass.log(objClass)

var swiftClass = SwiftClass()
swiftClass.log(10)
swiftClass.log("string")
swiftClass.log(objClass)

ObjClass の場合、すべてのメソッド呼び出しは Int32 型の最初のメソッドに対して行われます。COpaquePointerを使用すると、これがオブジェクト ポインターに関連していることがわかりますが、少し異なります。

ObjClass->Int32: 10
ObjClass->Int32: 1881422800
ObjClass->Int32: 1879122512

Swift クラスの Swift Extension は期待どおりに動作します。

SwiftClass->Int32: 10
SwiftClass->String: string
SwiftClass->ObjClass

うまくいけば、これはある時点でサポートされる可能性があります。それまでは、予期しない動作やクラッシュが発生するのではなく、コンパイル時に失敗するはずです。これに対して提案する回避策はありますか?

次のように、ObjClass 拡張メソッドを交換するかのように、最初のメソッドを呼び出していることがわかります。

extension ObjClass {
    func log(param: String)   { NSLog("ObjClass->String: " + param) }
    func log(param: Int32)    { NSLog("ObjClass->Int32: " + String(param)) }
    func log(param: ObjClass) { NSLog("ObjClass->ObjClass") }
}

次に、への呼び出しは正常にobjClass.log(str)機能しますが、への呼び出しはobjClass.log(10)次のようになります。

main(1): EXC_BAD_ACCESS (code=1, address=0xa)
4

1 に答える 1

7

ObjC はメソッドのオーバーロードをサポートしていません。ObjC クラスを拡張する場合、コードへのインターフェースは ObjC ランタイムです (そのクラスの Swift コードを他の Swift コードから呼び出している場合でも)。したがって、クラスのインターフェースは、そうでない Swift の機能を使用できません。 ObjC にも存在します。

ご指摘のとおり、これはおそらくコンパイル エラーです。特に便利なテストケースをすでにまとめているので、それについてバグを報告することをお勧めします。

于 2014-12-30T22:05:55.743 に答える