Swift方法重载推理不起作用

时间:2019-01-04 20:40:25

标签: swift generics overloading codable

我正在尝试为我的应用程序创建一个通用的JSON映射器。我正在使用Codable协议,并且有两个功能:一个将数据转换为可解码的功能,另一个将可编码转换为数据的功能。这是我的实现:

struct JSONMapper: JSONMapperProtocol {
    func map<T: Encodable>(from entity: T) -> Data? {
        let encoder = JSONEncoder()
        guard let data = try? encoder.encode(entity) else {
            return nil
        }

        return data
    }

    func map<T: Decodable>(from data: Data) -> T? {
        let decoder = JSONDecoder()
        guard let entity = try? decoder.decode(T.self, from: data) else {
            return nil
        }

        return entity
    }
}

这些功能的理想用法是:

if let body = requestData.body {
    request.httpBody = self.mapper.map(from: body)
}

requestData是此协议的实现:

protocol RequestData {
    var method: HTTPMethod { get }
    var host: String { get }
    var path: String { get }
    var header: [String: String]? { get }
    var queryParameters: [String: String]? { get }
    var body: Encodable? { get }
}

但是编译器给我以下错误:

  

无法将“可编码”类型的值转换为预期参数类型“数据”

我不知道为什么会这样,因为“ httpBody”是数据,“ body”是可编码的。编译器是否应该能够推断出这一点?

感谢您为解决此问题的任何想法。

配置:

编译器:Swift 4.2

Xcode:10.1

2 个答案:

答案 0 :(得分:0)

有关解码,请参见下文,有关编码,只需将JSONDecoder()更改为JSONEncoder()

let decoder = JSONDecoder()
if let data = response.data {
   do {
      let userList = try decoder.decode(UserList.self, from: data)
   }
   catch {
      print(error)
   }
}

使用它来解码响应数据,可以使用结构或类,然后将Codable作为类型。

struct UserList: Codable {
   var responseCode: String
   var response: UserListResponse
}

可以像上面那样具有可编码类型的层。

答案 1 :(得分:0)

您的方法的预期具体类型(T),它实现了协议Encodable<T: Encodable>)。

因此您不能以这种方式使用它,因为body必须是具体类型,因为Encodable只是应该实现它的struct / class的协议。您必须指定实现此协议的类型。


要实现此目的,您可以声明必须实现associatedtype协议的Encodable,然后可以将body的类型指定为此关联类型

protocol RequestData {
    ...
    associatedtype T: Encodable
    var body: T? { get }
}

然后在实现协议的struct / class内部,您必须将T的类型指定为实现协议Encodable的struct / class的具体类型

struct SomeStruct: RequestData {
    ...
    typealias T = SomeOtherStruct
    var body: T?
}

然后编译器不会给您任何错误,它应该可以工作:

request.httpBody = self.mapper.map(from: body)