Вывод перегрузки методом Swift не работает - PullRequest
0 голосов
/ 04 января 2019

Я пытаюсь создать универсальный картограф 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 }
}

Но компилятор выдает мне следующую ошибку:

Невозможно преобразовать значение типа 'Encodable' в ожидаемый тип аргумента 'Data'

Я не понимаю, почему это происходит, потому что 'httpBody' - это Данные, а 'body' - это Кодируемое. Разве компилятор не сможет это сделать?

Я ценю любые мысли, чтобы решить эту проблему.

Конфигурация:

Компилятор: Swift 4.2

Xcode: 10,1

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Ваш метод ожидает конкретный тип (T), который реализует протокол Encodable (<T: Encodable>).

Таким образом, вы не можете использовать его таким образом, потому что body должен быть конкретным типом, поскольку Encodable является просто протоколом для структуры / класса, который должен его реализовать. Вы должны указать, какой тип реализует этот протокол.


Для этого вы можете объявить associatedtype, который должен реализовывать протокол Encodable, а затем вы можете указать тип body в качестве этого связанного типа

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

затем внутри структуры / класса, который реализует ваш протокол, вы должны указать тип T как конкретный тип структуры / класса, который реализует протокол Encodable

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

тогда компилятор не выдаст вам ошибки и он должен работать:

request.httpBody = self.mapper.map(from: body)
0 голосов
/ 04 января 2019

Для декодирования см. Ниже, для кодирования просто измените JSONDecoder () на JSONEncoder ()

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

Используйте это для декодирования данных ответа, вы можете использовать struct или класс, а затем использовать Codable в качестве типа.

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

Которые, как и выше, могут иметь слои кодируемых типов.

...