Swift Generic func调用Generic func

时间:2017-11-04 14:09:51

标签: swift generics swift4

当使用一个泛型来调用另一个泛型时,我有一个有趣的编译错误。这篇文章有点长,但希望它不会超过描述问题所需的时间。

我已经定义了一个效果很好的通用函数。我经常使用它,使用模式通常是一样的。我试图实现一个嵌套现有泛型函数的新泛型函数,但我得到了一个编译时错误。

对于某些上下文,以下是我的API如何与通用工具一起使用。我的REST API调用films()func,它击中StarWarsAPI(swapi.co)并返回他们在数据库中拥有的所有星球大战电影的列表,如下所示:

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

films()函数调用泛型(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(通用)定义如下:(注意我使用Swift 4 Codable 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()
}

所以上面的作品很棒。我将它用于休息函数film(),people(),ships()等。我为每次休息调用使用相同的模式。我想创建一个我可以使用的泛型而不是显式的film(),people()等。

我一直试图让以下工作取得成功:

    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

非常感谢您提供的任何帮助!

1 个答案:

答案 0 :(得分:1)

您的电话必须是

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

请注意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)
    }
}