使用 Swift 中的可解码访问嵌入式 JSON 4

Accessing embedded JSON using decodable in Swift 4

我正在尝试访问特定的嵌入式字典数组来创建我的 swift 对象。我不确定如何访问 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:

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"

简单地定义一个包装器结构,它包含来自 JSON 响应的 results 属性。

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 枚举来覆盖它)。

So, first parse outer JSON , In new struct say StarWarsPeopleParent

class StarWarsPeopleParent: Decodable {
    var count: Int?
    var results: [StarWarsPeople]?
}

Update your StarWarsPeople struct's properties as:

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?
}

Then parse it like:

    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)")
        }
    }

希望您能理解。