You will have to implement your own func encode(to encoder: Encoder) throws
and init(from decoder: Decoder) throws
which are both properties of the Codable
protocol. Then change your rating
variable into an enum
Which would look like this:
enum Rating: Codable {
case int(Int)
case string(String)
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .int(let v): try container.encode(v)
case .string(let v): try container.encode(v)
}
}
init(from decoder: Decoder) throws {
let value = try decoder.singleValueContainer()
if let v = try? value.decode(Int.self) {
self = .int(v)
return
} else if let v = try? value.decode(String.self) {
self = .string(v)
return
}
throw Rating.ParseError.notRecognizedType(value)
}
enum ParseError: Error {
case notRecognizedType(Any)
}
}
Then on your DetailModel
just change rating: String
to rating: Rating
This works, I have tested with these JSON strings.
// int rating
{
"rating": 200,
"bro": "Success"
}
// string rating
{
"rating": "200",
"bro": "Success"
}
Edit: I've found a better swiftier way of implementing init(from decoder: Decoder) throws
, which produces a better error message, by using this you can now omit the ParseError
enum.
init(from decoder: Decoder) throws {
let value = try decoder.singleValueContainer()
do {
self = .int(try value.decode(Int.self))
} catch DecodingError.typeMismatch {
self = .string(try value.decode(String.self))
}
}