2016-05-21 24 views
0

私はSwiftでジェネリックスを実験していますが、私はそれを限界まで押し込もうとしています。Swiftジェネリックを使用して完了ブロックを使用したAPIリクエストを書く

私のアプリケーションでは、Alamofireの周りには単純なAPIラッパーがあります。構造はそうのようなものです:ここでは

API -> Request -> Alamofire request 

は、私はいくつかの概念をテストするために運動場に投げたいくつかの一般的なコードです。ここで私はこれまで持っているものである:関数を呼び出す

protocol SomeProtocol { 
    var cheese: String { get } 
    init() 
} 

class Something: SomeProtocol { 
    required init() { } 

    var cheese: String { 
     return "wiz" 
    } 
} 

class API { 

    class func performRequest<T: SomeProtocol>(completion: (T?, NSError) -> Void) { 

     // This code is irrelevant, just satisfying the completion param 
     let test = T() 
     let error = NSError(domain: "Pizza", code: 1, userInfo: nil) 

     completion(test, error) 
    } 

} 

func test() { 
    API.performRequest<Something> { item, error in 

    } 
} 

はエラーを与える:答えは1として

"Cannot explicitly specialize a generic function" 

****** ****** UPDATE

典型的な<>ジェネリック型指定子を削除し、期待される型を補完パラメータに追加することで問題が解決されます。ただ、簡単な例:

func test() { 
    API.performRequest { (item: Something?, error) in 

    } 
} 

また、私はAPIのラッパークラスを作成することは、一般的なクラスはそうのような問題を解決することを発見した:

protocol SomeProtocol { 
    var pizza: String { get } 
} 

class SomeObject: SomeProtocol { 
    var pizza: String { return "pie" } 
} 

class API<T: SomeProtocol> { 
    class func performRequest(completion: (T?, NSError?) -> Void) { 

    } 
} 

func test() { 
    API<SomeObject>.performRequest { item, error in 
     // Do something with item, which has a type of SomeObject 
    } 
} 

いずれかの方法で、最終目標が達成されます。私たちは、一連のタスクを実行し、それぞれの用途で渡された型に基づいてオブジェクトを完了クロージャで返す単一の汎用メソッドを持っています。

+0

私は、コンパイラが関数に適用する型を知らないと思います。クロージャでパラメータタイプを指定してみてください。 –

+0

ジェネリック薬を使用する目的を破ることはできませんか?私が理解しているところから、iOSは通常、スキャニングパラメータに基づいてタイプを推定します。完了クロージャはこれを適切にサポートしていないようです。 –

答えて

1

ジェネリックスの仕組みは、関数が実装内で未定義の変数を使用できるようにすることです。変数が指定されたプロトコルに準拠しなければならないことを指定することによって、これらの変数に機能を追加することができます(これは宣言内で行われます)。結果は、多くのタイプのテンプレートとして使用できる関数です。しかし、コード自体で関数が呼び出されると、コンパイラーは型を汎用化してジェネリックに適用できる必要があります。上記のコードで

、これはコンパイラは、それが明示的に指定せずに関数に適用する必要があります入力しているかを知ることができます

func test() { 
    API.performRequest { (item: Something?, error) in 

    } 
} 

func test() { 
    API.performRequest<Something> { item, error in 

    } 
} 

を交換してみてください。あなたが受け取ったエラーメッセージは今や意味をなさないはずです。

+0

ああ、私はあなたの最初の声明を誤解しました。あなたのコード例は完全な意味を持ちます。魅力的な作品!ありがとう! –

1

ここで私はalamofireとalamofireオブジェクトマッパーを使っていました: ステップ1:Mappableプロトコルに準拠したモーダルクラスを作成します。

class StoreListingModal: Mappable { 
var store: [StoreModal]? 
var status: String? 
required init?(_ map: Map){ 

} 

func mapping(map: Map) { 
    store <- map["result"] 
    status <- map["status"] 
} 
} 

ステップ2:ジェネリック型を使用して要求をフェッチ作成します。

func getDataFromNetwork<T:Mappable>(urlString: String, completion: (T?, NSError?) -> Void) { 
    Alamofire.request(.GET, urlString).responseObject { (response: Response<T, NSError>) in 
     guard response.result.isSuccess else{ 
      print("Error while fetching: \(response.result.error)") 
      completion(nil, response.result.error) 
      return 
     } 
     if let responseObject = response.result.value{ 
      print(responseObject) 
      completion(responseObject, nil) 
     } 
    } 
} 

ステップ3:今、あなたが必要とするすべての機能を取得し、これを呼び出すことです。これは次のようにすることができます。

self.getDataFromNetwork("your url string") { (userResponse:StoreListingModal?, error) in 

    } 

あなたは応答オブジェクトを取得するだけでなく、モーダルクラスにもマッピングされます。

関連する問題