Доступ к встроенному 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)")
        }
    }

Надеюсь, это хорошо для вас, чтобы понять.

Другие вопросы по тегам