2016-04-07 1 views
3

私は、次のスウィフトコードがあります。_convertNSDictionaryToDictionary <A、B where ...>(NSDictionary?) - > [A:B]なぜアプリケーションがクラッシュするのですか?

class ThingChecker { 
    static func checkThing() -> [String: [String]] { 
     return Thing.stringsDictionary() 
    } 
} 

Thingは、次のインターフェイスでのObjective-Cで実装クラスである:

@interface Thing : NSObject 

+ (NSDictionary<NSString *, NSArray<NSString *> *> * _Nonnull)stringsDictionary; 

@end 

しかし、私は私のアプリを実行し、ThingChecker.checkThing()を呼び出して、私のアプリを次のエラーでクラッシュします。

EXC_BAD_INSTRUCTION (code=EXC_i386_INVOP, subcode 0x0)

コンソールに何も表示されません。それはちょうど(lldb)を示しています。

enter image description here

見ても、リモートで便利な唯一のものは、デバッガのスタックトレースに含まれています。スタック内に2つのフレームがあり、少し手がかりが出るかもしれません。まず、あるちょうど私のコードの下:

_convertNSDictionaryToDictionary<A, B where ...> (NSDictionary?) -> [A : B] 

そして、ちょうどその下に、私は以下を参照してください。

_arrayForceCast<A, B> ([A]) -> [B] 

しかし、これらのいずれかをクリックするだけでアセンブリコードを指します。

ここでは何が起こっていますか?このクラッシュの原因は何ですか?私は完全に困惑している。

答えて

1

ラッピング対象のObjective-Cコードにバグがあります。

Objective-Cインターフェイスを作成した人は、ジェネリックアノテーションを追加してより有用な型情報を得るのに十分親切でした。

:スウィフトにかなり不便以下の署名で終わることから、刺激性のある

+ (NSDictionary *)stringsDictionary; 

:ジェネリック医薬品(およびNULL可能)注釈がなければ、誰かを遅延などのインタフェースを書かれている場合があります

など

しかし、Objective-Cのコードに追加ジェネリックとNULL可能注釈付き

class func stringsDictionary() -> [NSObject : AnyObject]! 
、:

+ (NSDictionary<NSString *, NSArray<NSString *> *> * _Nonnull)stringsDictionary; 

我々はスウィフト署名を消化する方がはるかに簡単で終わる:

class func stringsDictionary() -> [String: [String]] 

これは、文字列のキーと値として文字列の配列を持つ辞書であることは明らかです。

しかしObjective-CコードでObjective-C注釈は厳密には強制されません。彼らは単なる提案です。そして、ジェネリックのアノテーションは厳密には強制されません。

は、したがって、これらのObjective-Cのジェネリック注釈を印加することにより、ブリッジングの過程で、スウィフトは、あなたの質問に記載された方法で呼び出します。

_convertNSDictionaryToDictionary<A, B where ...> (NSDictionary?) -> [A : B] 

これは、Objective-CのからNSDictionaryがに変換する方法でありますスウィフト辞書しかし実際の辞書の内容がジェネリックスの署名(およびSwiftがタイプを推論するタイプ)と一致しない場合、このクラッシュが発生します。

効果的に、このクラッシュは、as!演算子を使用しようとしたときに、キャストに失敗した場合のクラッシュとほぼ同じです。例えば

let someDict: AnyObject = ["foo": ["a", "b", "c"], "bar": [1, 2, 3]] 
let stringDict = someDict as! [String: [String]] 

このキャストは失敗し、someDict[String: [String]]として解釈することはできませんので、あなたのアプリがクラッシュしていました。せいぜい、[String: [Any]]と解釈することができます。スイフトからこのメソッドを呼び出そうと

+ (NSDictionary<NSString *, NSArray<NSString *> *> * _Nonnull)stringsDictionary { 
    return @{ @"foo": @[@"foo1", @"foo2", @"foo3", @"foo4", @"foo5"], 
       @"bar": @[@1, @2, @3, @4, @5], 
       @"baz": @[@"baz1", @"baz2", @"baz3", @"baz4", @"baz5"] }; 
} 

キー@"bar"それ値ので、正確なエラーメッセージを生成します。例えば、そのObjective-Cのメソッドの実装は次のように見えるのであれば

NSNumberオブジェクトの配列なので、せいぜいSwiftの[String: [Any]]として扱うことができます。

そして、我々は、以下のようなObjective-Cの一般的な注釈修正することができます:

+ (NSDictionary<NSString *, NSArray *> * _Nonnull)stringsDictionary; 

それとも、私たちは実装を修正し、間違っているように見える価値を取り除くことができます(メソッドがstringsDictionaryと呼ばれているのでNSNumberの値は明らかに文字列ではありません)。

関連する問題

 関連する問題