Мне возвращают логическое значение в «нескольких» различных форматах с сервера (для одной и той же структуры и поля). Я знаю, что это нелепо, но мне нужно найти способ аккуратно с ним справиться.
Поэтому для десериализации я делаю что-то вроде (пример программы):
import Foundation
struct Foo: Codable {
var isOpen: Bool?
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
isOpen = try container.decodeIfPresent(Bool.self, forKey: .isOpen)
}
enum CodingKeys: String, CodingKey {
case isOpen
}
}
//He sends any one of these..
let json1 = "{ \"isOpen\": \"true\" }"
let json2 = "{ \"isOpen\": \"false\" }"
let json3 = "{ \"isOpen\": true }"
let json4 = "{ \"isOpen\": false }"
let json5 = "{ \"isOpen\": null }"
let json6 = "{ \"isOpen\": \"null\" }"
let json7 = "{ \"isOpen\": \"<null>\" }"
//He doesn't send this one.. but I wouldn't be surprised if I got it so I added it for fun (serializing the below `json8` and `json9` is not required for an answer).. :)
let json8 = "{ \"isOpen\": 0 }"
let json9 = "{ \"isOpen\": 1 }"
let json = [json1, json2, json3, json4, json5, json6, json7, json8, json9]
for js in json {
if let rawData = js.data(using: .utf8) {
do {
let foo = try JSONDecoder().decode(Foo.self, from: rawData)
if let isOpen = foo.isOpen {
print("\(isOpen)\n\n")
} else {
print("State Unknown\n\n")
}
} catch {
print("\(error)\n\n")
}
}
}
Теперь, если я использую Swift Codable (который уже используется всеми нашими структурами данных), мы получим несоответствие типов иошибка / исключение выдается.Я думал о том, чтобы попытаться перехватить каждый случай и попробовать другой декодер с другим типом, но тогда это закончится примерно так:
do {
isOpen = try container.decode(Bool.self, forKey: .isOpen)
}
catch {
do {
isOpen = try container.decode(Int.self, forKey: .isOpen) != 0
}
catch {
do {
isOpen = Bool(try container.decode(String.self, forKey: .isOpen))
}
catch {
do {
isOpen = try container.decodeIfPreset(Bool.self, forKey: .isOpen) ?? GiveUpAndAssignDefaultValueHere..
}
catch {
isOpen = nil //no idea..
}
}
}
}
Тогда я подумал о том, чтобы сначала преобразовать его в строку, а затем попытаться разобратьчто вместо этого я закончил с (по крайней мере, лучше, чем выше):
do {
isOpen = try container.decode(Bool?.self, forKey: .isOpen)
}
catch {
do {
isOpen = Bool(try container.decode(String.self, forKey: .isOpen))
}
catch {
isOpen = try container.decode(Int.self, forKey: .isOpen) != 0
}
}
но, конечно, есть лучший способ?Есть идеи ???