#json #swift #codable
#json #swift #кодируемый
Вопрос:
Я использую Swift впервые, и я хотел бы иметь возможность обрабатывать некоторую информацию из ответа API в полезный объект Swift.
У меня есть (например) следующие данные, возвращающиеся из моего API:
{
data: [{
id: 1,
name: "Fred",
info: {
faveColor: "red",
faveShow: "Game of Thrones",
faveIceCream: "Chocolate",
faveSport: "Hockey",
},
age: "28",
location: "The Moon",
},{
...
}]
}
В swift я data
возвращаюсь из API. Я получаю первый объект, конвертирую его и получаю к нему доступ следующим образом:
let json = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
let dataParentNode = json["data"] as! [[String:Any]]
let firstObject = dataParentNode[0]
let _id = firstObject["id"] as? String ?? "0"
let _name = firstObject["name"] as? String ?? "Unknown"
Это нормально, пока я не захочу начать обработку подобъектов, принадлежащих первому объекту, поэтому я придумал следующие struct
действия, чтобы попытаться сделать это более чистым.
Пожалуйста, обратите внимание — мне не нужно обрабатывать все возвращаемые данные JSON, поэтому я хочу преобразовать их в то, что мне нужно в структурах
struct PersonInfo : Codable {
let faveColor: String?
let faveShow: String?
}
struct Person : Codable {
let id: String?
let name: String?
let info: PersonInfo?
}
Когда я беру это:
let json = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
let dataParentNode = json["data"] as! [[String:Any]]
let firstObject = dataParentNode[0]
а затем попытайтесь преобразовать firstObject
в Person
или firstObject["info"]
в PersonInfo
, кажется, я не могу заставить его работать (я получаю nil
).
let personInfo = firstObject["info"] as? PersonInfo
Кто-нибудь может посоветовать, пожалуйста? Мне просто нужно разобраться с получением данных ответа API и сопоставлением их с заданной структурой (с подобъектами), игнорируя ключи, которые мне не нужны.
Комментарии:
1.
let personInfo = firstObject as? PersonInfo
,firstObject as? PersonInfo
равно нулю, потомуfirstObject
что не переносится как PersonInfo, в лучшем случае это словарь.let personInfo = PersonInfo(faveColor: firstObject["faveColor"] as? String ?? "Unknown color", faveShow: firstObject["faveColor"] as? String ?? "Unknown show")
2. @Larme — извините, это была опечатка.
firstObject
это первый результат в массиве изdata
JSON, поэтому он должен быть:let personInfo = firstObject["info"] as? PersonInfo
в моем OP3.
let personInfoDict = firstObject["info"] as? [String: Any]
, иlet personInfo = PersonInfo(faveColor: personInfoDict["faveColor"] as? String ?? "Unknown color", faveShow: personInfoDict["faveColor"] as? String ?? "Unknown show")
Ответ №1:
Для этого вы можете просто использовать decode(_:from:)
function of JSONDecoder
:
let decoder = JSONDecoder()
do {
let decoded = try decoder.decode([String: [Person]].self, from: data)
let firstObject = decoded["data"]?.first
} catch {
print(error)
}
Еще лучше, если вы можете добавить к своей модели другую структуру, подобную этой:
struct PersonsData: Codable {
let data: [Person]
}
И сопоставьте свой JSON с использованием этого типа:
let decoder = JSONDecoder()
do {
let decoded = try decoder.decode(PersonsData.self, from: data)
let firstObject = decoded.data.first
} catch {
print(error)
}
Обновление: ваша структура Person может потребовать небольшого изменения, поскольку свойство id в вашем JSON является целым числом.
Итак, это закончится так:
struct Person : Codable {
let id: Int?
let name: String?
let info: PersonInfo?
}
Комментарии:
1. Еще раз спасибо за это. Это был ответ для меня. Я пытался сделать что-то подобное, но все равно получил ошибку. Оказывается, я не заметил потенциального изменения в ответе API, которое мне нужно было учесть. Теперь все работает и код намного чище!