How would you write the decoding code for the following JSON:
{
"identifier": "1",
"issuer": "visa",
"pattern": [5, [7, 9]]
}
To map it into the following model:
struct Card: Decodable {
let identifier: String
let issuer: String
let pattern: [CardPattern]
}
enum CardPattern: Decodable {
case prefix(Int)
case range(start: Int, end: Int)
}
Notice how the pattern
attribute in the json is a collection of two possible values:
Int
indicating we should map into aCardPattern.prefix
case[Int]
containing two values, indicating we should map into aCardPattern.range
case (first value isstart
, second value isend
)
CodePudding user response:
Read about the singleValueContainer
it should solve your problem.
Here is a working snippet with testing...
enum CardPattern: Codable {
case prefix(Int)
case range(start: Int, end: Int)
init(from decoder: Decoder) throws {
let singleContainer = try decoder.singleValueContainer()
do {
let prefix = try singleContainer.decode(Int.self)
self = .prefix(prefix)
return
} catch {
print("Not a prefix")
}
do {
let range = try singleContainer.decode([Int].self)
self = .range(start: range[0], end: range[1])
return
} catch {
print("Not a range")
}
throw NSError(domain: "Unknown type", code: -1)
}
func encode(to encoder: Encoder) throws {
var singleContainer = encoder.singleValueContainer()
switch self {
case .prefix(let value):
try singleContainer.encode(value)
case .range(start: let start, end: let end):
let range: [Int] = [start, end]
try singleContainer.encode(range)
}
}
}
let data = [CardPattern.prefix(10), CardPattern.range(start: 2, end: 9)]
var encodedData: Data = Data()
do {
encodedData = try JSONEncoder().encode(data)
print(encodedData)
} catch {
print("encode")
print(error)
}
do {
let decoded = try JSONDecoder().decode([CardPattern].self, from: encodedData)
print(decoded)
} catch {
print("decode")
print(error)
}