如何在Swift中创建一个返回可解码类型的函数?

时间:2019-12-13 11:44:39

标签: swift generics codable

所以我有这个枚举,可用于我在应用程序中使用的几个url请求:

enum Netwrok {
    case popular
    case topRated
    case latest
    // ...

    static let baseUrl = "http://..."

    func path() -> String {
        switch self {
            case .popular: return "/popular"
            // ...
        }
     }
}

我想添加一个函数,该函数返回网络堆栈应使用其解码数据的模型的Decodable Type。

所以我认为类似的事情会做得到:

    func returnType<T>() -> T.Type where T : Decodable {
        switch self {
        case .popular:
            return Popular.self
        // ...
        }
    }

但是我无法使其正常工作,它说:

  

无法将类型“ Popular.Type”的返回表达式转换为类型“ T.Type”

要求我强制投放T.Type

如何制作一个返回可解码的函数,以便可以处理类型,但可以使用JSONDecoder的解码函数?

谢谢。

3 个答案:

答案 0 :(得分:2)

您要问的很简单,但可能不是您想要的。您要执行的操作是返回一个类型。没什么通用的。

func returnType<T>() -> T.Type where T : Decodable {

此语法定义了一个类型参数T,该类型参数由调用方传递。它不是由您的函数定义的。这意味着调用方可以传递可解码的 any 类型,您的函数将返回该类型。例如,呼叫者可以将T设置为Int(因为它是可解码的),然后您将返回Int.Type。这很容易实现(return T.self,但不是您的意思。

您的意思是该函数返回该函数知道的某种可解码的类型,但调用者却不知道:

func returnType() -> Decodable.Type { ... }

这可以正常工作,并且可以完全满足您的要求,但这表明您可能不正确地构建了该网络堆栈,以后会头疼。

这种方法可能会引起问题的原因是您可能想编写如下代码:

let result = JSONDecoder().decode(networkType.returnType(), from: data)

这将被打破,因为Decodable.Type不是本身可解码的类型。 (您可以解码Int,但不能解码Int的 type 。)说它确实有效。 result是什么类型?你能用它做什么?您唯一要知道的是它是可解码的(并且您已经对其进行了解码)。

您可能想要更多类似Vasu Chand的实现或the similar approach discussed in my blog series

答案 1 :(得分:1)

对于API调用的返回结果,可以使用转义闭包

假设您正在命中一个get请求。一个简单的工作示例,用于将Codable模型传递给get请求api。

class func GETRequest<ResponseType :Decodable>(url : URL,responseType : ResponseType.Type ,completion: @escaping (ResponseType? ,Error? ) -> Void){


        var request = URLRequest(url: url)
        request.httpMethod = "GET"

        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

            guard let data = data else{

                completion(nil,error)
                return
            }

          let decoder = JSONDecoder()

            do{
                let responseData = try decoder.decode(ResponseType.self, from: data)

                completion(responseData, nil)

            }
            catch let error{

                completion(nil, error)


            }
        }
        task.resume()   

 }

如何调用此网络功能。

Network.GETRequest(url: url, responseType: Model.self) { (model, error) in
            completion(model,error)
 }

模型类包含

struct Model : Codable{

}

您可以将任何get请求的任何响应模型传递给网络类。

类似地,您可以在请求主体只是可编码模型的情况下为后期请求构建api网络。

答案 2 :(得分:0)

对不起,您不能根据您的需要在此处提供第一个参数

JSONDecoder().decode(AdecodableType.self,from:data)

在编写代码时必须正确推断,因此它不能是符合Decodable

的类型集合中的Any 1