2017-11-04 12 views
1

ジェネリック関数を使用して別のジェネリック関数を呼び出す際に、面白いコンパイルエラーが発生します。この投稿は少し長めですが、うまくいけば、問題を説明するのに必要以上に長くはありません。Swiftジェネリック関数を呼び出す汎用関数

私は優れた汎用funcを定義しました。私はそれをたくさん使用し、使用のパターンはしばしば同じです。私は、既存の汎用関数をネストする新しい汎用関数を実装しようとしていましたが、コンパイル時にエラーが発生しました。

いくつかの文脈では、ここで私のAPIがジェネリックとどのように機能するかを示します。

StarWarsAPI.shared.films(){ (films, error) in 
     for film in films { 
       print(film.title) 
     } 
} 

フィルム(:私のREST APIはStarWarsAPI(swapi.co)に当たると、以下のように、彼らは彼らのデータベースを持っているすべてのスターウォーズ映画のリストを返しフィルム呼び出し()FUNCを作ります)関数は汎用的な関数(restCall())を呼び出します。

public func films(completion: @escaping (_ films:[Film]?, _ error:StarWarsError?) -> Void) { 
    guard StarWarsAPI.isOperational else { 
     return completion(nil,StarWarsError.starWarsAPINotOperational) 

    } 
    restCall(fetchUrl: filmsUrl!, modelType: FilmResult()) { (filmResults, error) in 
     completion(filmResults?.results, error) 
    } 
} 

次のようにrestCall(ジェネリック)が定義されます:(私はスウィフト4コード可能なAPIを使用しています)だから、

public func restCall<T: Codable>(fetchUrl: URL, modelType: T, completion: @escaping (_ modelObject: T?, _ error:StarWarsError?) -> Void){ 

    var fetchRequest = URLRequest(url: fetchUrl, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) 

    fetchRequest.httpMethod = "GET" 
    fetchRequest.allHTTPHeaderFields = [ 
     "content-type": "application/json", 
     "cache-control": "no-cache", 
    ] 

    let session = URLSession.shared 
    let fetchDataTask = session.dataTask(with: fetchRequest) { (data, response, error) in 

     DispatchQueue.main.async { // return to main thread 


      var modelObject:T? 
      do { 

       let jsonDecoder = JSONDecoder() 
       modelObject = try jsonDecoder.decode(T.self, from: data)// FIXME: Something about decoding the People object is going wrong. 
       return completion(modelObject, nil) 

      }catch let error as NSError { 
       completion(nil, StarWarsError.decodingModelError(error: error)) 
      } 
     } 
    } 

    fetchDataTask.resume() 
} 

上記ここでフィルムの定義は()でありますよく働く。私は残りの機能のフィルム()、人()、船()などのためにそれを使用します。私は休憩ごとに同じパターンを使用します。私は私が取得しようとしてきた

私が代わりに明示的なフィルム()、人()などの使用することができ、一般的な作成したいほとんど成功で作業するには、次

public func fetchAll<T: Result>(result:T, completionAll: @escaping (_ result:T?, _ error:StarWarsError?) -> Void) { 

     restCall(fetchUrl: result.urlPath!, modelType: T) { (finalResults, error) in 
      completionAll(finalResults!, error) 
     } 

    } 

結果の型は基本型で、次のように定義されています。私は取得していますエラーは以下のスクリーンショットに示されている

public class Result { 
    var urlPath:URL? 
} 
public class FilmResult: Result, Codable { 

    var count:Int? 
    var next:String? 
    var previous:String? 
    var results:[Film]? 

} 

- うまくいけば、それは明らかです。

enter image description here

あなたが提供できるすべてのヘルプははるかに高く評価されるだろう!あなたの呼び出しが

     this was T previously ───┐ 
restCall(fetchUrl: result.urlPath!, modelType: result) { (finalResults, error) in 

にする必要があり

答えて

1

result代わりのTに注意してください。再現する


比較的最小限のコード:

public func restCall<T>(fetchUrl: URL, modelType: T, completion: @escaping (_ modelObject: T?, _ error:String?) -> Void) { } 

public func fetchAll<T>(result:T, completionAll: @escaping (_ result:T?, _ error:String?) -> Void) { 

                  ┌── should be result 
    restCall(fetchUrl: URL(string: "asdasd")!, modelType: T) { (finalResults, error) in 
     completionAll(finalResults, error) 
    } 
} 
+0

ありがとうございます!これは動作します! – RMH

関連する問題