2016-07-11 21 views
1

私は継承したWeb APIフレームワークにエラー処理を追加しています。現時点では強制的なキャストが行われていますが、データが予期したものと一致しないとクラッシュする可能性があります。Swiftでジェネリック型チェック機能を使用できますか?

as!のすべての用途をタイプをチェックし、失敗した場合に例外(詳細な説明付き)をスローする機能に置き換えたいと思います。

func checkType<T>(type: AnyClass, value: T?, name: String) throws -> T { 
    guard let value = value else { 
     let message = "[\(name)] Expected \(type), but value was nil" 
     throw PlaidsterError.InvalidType(message) 
    } 

    guard value.dynamicType.self == type else { 
     let message = "[\(name)] Expected \(type), but it was an \(value.dynamicType.self) with value: \(value)" 
     throw PlaidsterError.InvalidType(message) 
    } 

    return value 
} 

しかし、これは複数の問題があります。

これは私がする、これまでに得たものです。それはオブジェクト型だけを取ることができますが、クラスが正確に一致しない場合(たとえばNSStringが実際に__NSCFStringなので失敗した場合)、失敗します。つまり、String型、Int型、Double型のいずれでも動作しません...

Any値型の同義語AnyClassが見つかりません。これは最初の問題です。またtypeはタイプではないと言われているので、value.dynamicType.self is typeのようなことはできません。


それは私がやろうとしている何をすることは可能ですか?この種類の型チェックを行うには、解析コード全体に散らばった定型のコードがたくさんなくても良い方法がありますか?あなたは他のジェネリック型パラメータを指定して、このような何かを書くことができます

public struct PlaidCategory { 

    // MARK: Properties 
    public let id: String 
    public let hierarchy: [String] 
    public let type: String 

    // MARK: Initialization 
    public init(category: [String: Any]) throws { 
     id = try checkType(String.self, value: category["id"], name: "id") 
     hierarchy = try checkType([String].self, value: category["hierarchy"], name: "hierarchy") 
     type = try checkType(String.self, value: category["type"], name: "type") 
} 

}

+0

私はあなたがgithubの上の多数の迅速なJSONパーサーの1を見て、あなたが何かを見つけることができるかどうかを確認示唆興味深い "github swift json"。 SwiftyJSON、光沢など。 – Mattias

答えて

3

私の目標は、このまたはさらに簡単なような何かを得ることです。

func checkType<T, U>(type: U.Type, value: T?, name: String) throws -> U { 
    guard let value = value else { 
     let message = "[\(name)] Expected \(type), but value was nil" 
     throw PlaidsterError.InvalidType(message) 
    } 

    guard let result = value as? U else { 
     let message = "[\(name)] Expected \(type), but it was an \(value.dynamicType) with value: \(value)" 
     throw PlaidsterError.InvalidType(message) 
    } 

    return result 
} 

としてそれを使用する:

do { 
    let n: Any = 3 
    let t = try checkType(Int.self, value: n, name: "n") 
    print(t) //->3 
} catch let error { 
    print(error) 
} 
do { 
    let n: Any = "x" 
    let t = try checkType(Int.self, value: n, name: "n") 
    print(t) 
} catch let error { 
    print(error) //->InvalidType("[n] Expected Int, but it was an _NSContiguousString with value: x") 
} 

私は、これはあなたのPlaidCategory.init(category:)のために働くことを願っていますが、テストされていません。


もう1つ。戻り値の型が推測可能な場所でのみ使用する場合は、typeパラメータを渡す必要はありません。

func checkType<T, U>(value: T?, name: String) throws -> U { 
    guard let value = value else { 
     let message = "[\(name)] Expected \(U.self), but value was nil" 
     throw PlaidsterError.InvalidType(message) 
    } 

    guard let result = value as? U else { 
     let message = "[\(name)] Expected \(U.self), but it was an \(value.dynamicType) with value: \(value)" 
     throw PlaidsterError.InvalidType(message) 
    } 

    return result 
} 

としてそれを使用する:

do { 
    let n: Any = "x" 
    let t: Int = try checkType(n, name: "n") 
    print(t) 
} catch let error { 
    print(error) //->InvalidType("[n] Expected Int, but it was an String with value: x") 
} 

か:

public struct PlaidCategory { 

    // MARK: Properties 
    public let id: String 
    public let hierarchy: [String] 
    public let type: String 

    // MARK: Initialization 
    public init(category: [String: Any]) throws { 
     id = try checkType(category["id"], name: "id") 
     hierarchy = try checkType(category["hierarchy"], name: "hierarchy") 
     type = try checkType(category["type"], name: "type") 
    } 
} 
+0

これは完璧です!私はタイプのジェネリックも考えていなかったとは信じられない!あなたの2番目の答えは美しく動作し(プレイグラウンドでテストされています)、さらに簡潔です。 –

+0

また、私はJSONを解析しているので、値を取得するために辞書を専有しているので、名前を2回入力する必要性を取り除くために、2番目の便利な関数を追加しました: 'func checkType (dictionary:Dictionary 、name:String )throws - > U {let value =辞書[名前];戻り値checkType(value、name:name)} ' –

関連する問題