Допустим, у вас есть JSON:
{
"status": "error",
"data": {
"errormessage": "Could not get user with ID: -1.",
"errorcode": 14
}
}
Для заданной структуры Error:
struct APIError: Decodable {
let code: Int?
let message: String?
enum CodingKeys: String, CodingKey {
case code = "errorcode"
case message = "errormessage"
}
}
Нажмите на веб-сервис, получите JSON и инициализируйте структуру:
let urlRequest = URLRequest(url: url)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest)
{ (data, response, error) in
// Doesn't work because the portion of the JSON we want is in the "data" key
let e = try? JSONDecoder().decode(APIError.self, from: data)
}
task.resume()
Есть ли простой способ сделать что-то вроде data["data"]
? Какой правильной модели следовать?
Решение А. Преобразуйте данные в объект JSON, получите нужный объект, затем преобразуйте его в объект данных и выполните декодирование.
let jsonFull = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any]
let json = jsonFull["data"]
let data_error = try? JSONSerialization.data(withJSONObject: json, options: [])
let e = try? JSONDecoder().decode(APIError.self, from: data_error)
Решение Б. Оберните целевой элемент в другую структуру
struct temp : Decodable {
let status: String?
let data: APIError?
}
let e = try? JSONDecoder().decode(temp.self, from: data).data
Решение C. Установите вложенную структуру в декодировании (что, если это несколько объектов в глубину?)
let e = try? JSONDecoder().decode([Any, APIError.self], from: data)
Какие шаблоны мне не хватает? Какой самый элегантный способ сделать это?
Any
не поддерживается). Существует решение D с использованиемnestedContainers
, но в этом случае решение B является обычным. - person vadian   schedule 24.01.2018