Недавно я работал с API запросом, ответом от которого был JSON, в котором одно из значений могло быть либо Bool, либо String.
Ответ от сервера мог быть таким:
{
"title": "Test",
"coverImage": false,
"coverImageFilename": false
}
Или таким:
{
"title": "Test",
"coverImage": "https://website.com/coverimage.jpg",
"coverImageFilename": "coverimage.jpg"
}
В данном случае если у страницы включена Cover Image, даётся ссылка и название файла. Если картинка не установлена - возвращается false.
Проблема заключалась в том, что структура, написанная под этот json-ответ, не позволяла правильно декодить полученный ответ:
struct PageDetails: Codable {
public let title: String
public let coverImage: Bool
public let coverImageFilename: Bool
}
В одном случае coverImage был Bool, в другом - String, что вызывало ошибку.
Решение
struct ValueOrFalse<T:Codable>: Codable {
let value: T?
public init(from decoder:Decoder) throws {
let container = try decoder.singleValueContainer()
let falseValue = try? container.decode(Bool.self)
if falseValue == nil {
value = try container.decode(T.self)
} else {
value = nil
}
}
}
Использовать её очень просто:
struct PageDetails: Codable {
public let title: String
public let coverImage: ValueOrFalse<String>
public let coverImageFilename: ValueOrFalse<String>
}
let myJson = """
{
"title": "Test",
"coverImage": false,
"coverImageFilename": false
}
"""
do {
print(try JSONDecoder().decode(PageDetails.self, from: myJson.data(using: .utf8)!))
} catch {
print(error)
}