Доступ к встроенному JSON с использованием декодируемого в Swift 4
Я пытаюсь получить доступ к определенному встроенному массиву словарей для создания моих быстрых объектов. Я не уверен, как получить доступ к этому массиву в словаре JSON.
Вот определение моего объекта Swift = StarWarsPeople
class StarWarsPeople: Decodable {
var name: String?
var height: String?
var weight: String?
var hair_color: String?
var skin_color: String?
var eye_color: String?
var birth_year: String?
var gender: String?
}
Вот мой класс APIClient:
class StarWarsPeopleAPIClient
{
class func getStarWarsPeopleInformation (page: Int, completion:@escaping ([StarWarsPeople])-> ()) throws {
let starWarsPeopleURL = "https://swapi.co/api/people/?page=\(page)"
let convertedStarWarsPeopleURL = URL(string: starWarsPeopleURL)
guard let unwrappedConvertedStarWarsPeopleURL = convertedStarWarsPeopleURL else { print("unwrappedConvertedStarWarsPeopleURL did not unwrap"); return}
let request = URLRequest(url: unwrappedConvertedStarWarsPeopleURL)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let unwrappedData = data else { print("unwrappedData did not unwrap"); return}
do {
let starWarsPeopleDataArray = try JSONDecoder().decode([StarWarsPeople].self, from: unwrappedData)
completion(starWarsPeopleDataArray)
}
catch let error {
print("Error occured here: \(error.localizedDescription)")
}
}
task.resume()
}
}
Вот мой Json, это массив результатов, к которому я хотел бы получить доступ, это массив словарей, которые мне нужно перебрать, чтобы создать мой объект StarWarsPeople.
{
"count": 87,
"next": "url",
"previous": null,
"results": [
{
"name": "Luke Skywalker",
"height": "172",
"mass": "77",
"hair_color": "blond",
"skin_color": "fair",
"eye_color": "blue",
"birth_year": "19BBY",
"gender": "male",
"homeworld": "url",
"films": [
"url",
"url",
"url",
"url",
"url"
],
"species": [
"url"
],
"vehicles": [
"url",
"url"
3 ответа
Просто определите структуру оболочки, которая содержит results
свойство из ответа JSON.
struct ApiResponse: Decodable {
results: [StarWarsPeople]
}
и позже использовать
let apiResponse = try JSONDecoder().decode(ApiResponse.self, from: unwrappedData)
let starWarsPeopleDataArray = apiResponse.results
разобрать это.
Пожалуйста, прочитайте JSON. Вы игнорируете вмещающий объект
struct Root: Decodable {
let count: Int
let next: URL?
let previous: URL?
let results : [StarWarsPeople]
}
struct StarWarsPeople: Decodable {
private enum CodingKeys: String, CodingKey {
case name, height, mass
case hairColor = "hair_color", skinColor = "skin_color"
case eyeColor = "eye_color", birthYear = "birth_year", gender
}
let name: String
let height: String
let mass: String
let hairColor: String
let skinColor: String
let eyeColor: String
let birthYear: String
let gender: String
}
...
let root = try JSONDecoder().decode(Root.self, from: unwrappedData)
let starWarsPeopleDataArray = root.results
...
Заметки:
- Структура достаточна.
- Сопоставьте ключи snake_cased со свойствами camelCased.
- Почти во всех случаях свойства могут быть объявлены как константы (
let
). - Не объявляйте все свойства схематически как необязательные. Объявите в качестве необязательных только те, для которых соответствующий ключ может отсутствовать или значение может быть
null
,
Результаты, которые вы пытаетесь получить, на самом деле присутствуют в results
ключи. Также нам нужно использовать свойства, такие же как имя параметра (мы можем использовать также перечисление CodingKeys для переопределения этого).
Итак, сначала разбери внешний JSON, в новой структуре скажи
StarWarsPeopleParent
class StarWarsPeopleParent: Decodable {
var count: Int?
var results: [StarWarsPeople]?
}
Обновите свой
StarWarsPeople
Свойства структуры как:
class StarWarsPeople: Decodable {
var name: String?
var height: String?
var mass: String?
var hair_color: String?
var skin_color: String?
var eye_color: String?
var birth_year: String?
var gender: String?
}
Затем проанализируйте это как:
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let unwrappedData = data else { print("unwrappedData did not unwrap"); return}
do {
let starWarsPeopleDataArray = try JSONDecoder().decode(StarWarsPeopleParent.self, from: unwrappedData)
completion(starWarsPeopleDataArray)
}
catch let error {
print("Error occured here: \(error.localizedDescription)")
}
}
Надеюсь, это хорошо для вас, чтобы понять.