Как насчет этого ...
Объявить протокол PayloadType
...
protocol PayloadType: Decodable { }
и заставить String
и struct Payload
соответствовать ему ...
extension String: PayloadType { }
struct Payload: Decodable, PayloadType {
let someInt: Int
let someString: String
}
Затем сделайте GenericResponseModel
универсальный…
struct GenericResponseModel<T: PayloadType>: Decodable {
let status: String
let payload: T
enum CodingKeys: CodingKey {
case status, payload
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
status = try container.decode(String.self, forKey: .status)
payload = try container.decode(T.self, forKey: .payload)
}
}
Затем вы сможете расшифровать его следующим образом…
let data = """
{
"status" : "OK",
"payload" : "nothing changed"
}
""".data(using: .utf8)!
print(try JSONDecoder().decode(GenericResponseModel<String>.self, from: data))
// GenericResponseModel<String>(status: "OK", payload: "nothing changed")
и
let data2 = """
{
"status" : "OK",
"payload" : {
"someInt" : 2,
"someString" : "hi"
}
}
""".data(using: .utf8)!
print(try JSONDecoder().decode(GenericResponseModel<Payload>.self, from: data2))
// GenericResponseModel<Payload>(status: "OK", payload: Payload(someInt: 2, someString: "hi"))
Конечно,это зависит от того, знаете ли вы заранее тип payload
.Вы можете обойти это, выдав конкретную ошибку, если полезный груз имеет неправильный тип…
enum GenericResponseModelError: Error {
case wrongPayloadType
}
, а затем…
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
status = try container.decode(String.self, forKey: .status)
do {
payload = try container.decode(T.self, forKey: .payload)
} catch {
throw GenericResponseModelError.wrongPayloadType
}
}
Затем обработайте эту ошибку при декодировании…
let data = """
{
"status" : "OK",
"payload" : {
"someInt" : 2,
"someString" : "hi"
}
}
""".data(using: .utf8)!
do {
let response = try JSONDecoder().decode(GenericResponseModel<String>.self, from: data) // Throws
print(response)
} catch let error as GenericResponseModelError where error == .wrongPayloadType {
let response = try JSONDecoder().decode(GenericResponseModel<Payload>.self, from: data2) // Success!
print(response)
}