繁体   English   中英

如何从复杂的 json 创建简单的可编码结构

[英]How to create simple codable struct from complex json

我从 API 收到了一个类似于此的复杂 json 响应。

{
    "result": "success",
    "count": 100,
    "details": [{
            "unnecessaryDetails": "something",
            "area": {
                "name": "Test1"
            }
        },
        {
            "unnecessaryDetails": "something",
            "area": {
                "name": "Test2"
            }
        },
        {
            "unnecessaryDetails": "something",
            "area": {
                "name": "Test3"
            }
        }
    ]
}

我的结构是

struct Person {
    var name: String
}

struct Response {
    var result: String
    var count: Int
    var details: [Person]
}

我不想为我从响应中收到的所有内容创建属性。 我不能要求后端开发人员只提供必要的详细信息。 如何避免不必要的细节并仅使用需要的细节创建结构?

您可以跳过带有嵌套容器的中间数组和字典。

struct Person : Decodable {
    let name: String
}

struct Response : Decodable {
    let result: String
    let count: Int
    let details: [Person]

    enum CodingKeys: String, CodingKey { case result, count, details }
    enum DetailCodingKeys: String, CodingKey { case area }

    init(from decoder : Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        result = try container.decode(String.self, forKey: .result)
        count = try container.decode(Int.self, forKey: .count)
        var detailContainer = try container.nestedUnkeyedContainer(forKey: .details)
        var people = [Person]()
        while !detailContainer.isAtEnd {
            let areaContainer = try detailContainer.nestedContainer(keyedBy: DetailCodingKeys.self)
            let person = try areaContainer.decode(Person.self, forKey: .area)
            people.append(person)
        }
        details = people
    }
}

然而,工作量比添加额外的结构要大得多

struct Response : Decodable {
    let result: String
    let count: Int
    let details: [Detail]
}

struct Detail : Decodable {
    let area : Person
}

struct Person : Decodable {
    let name: String
}

您可以使用Codable仅解析您要解析的属性,其余的将被忽略,如果您想在 2 个单独的模型中解析 json,则可以按照此问题的答案进行操作。

是否可以将单级 JSON 解码为 2 个单独的模型?

使用Codable (根据需要删除字段):

import Foundation

struct Response : Codable {
    let result : String?
    let count : Int?
    let details : [Details]?

    enum CodingKeys: String, CodingKey {

        case result = "result"
        case count = "count"
        case details = "details"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        result = try values.decodeIfPresent(String.self, forKey: .result)
        count = try values.decodeIfPresent(Int.self, forKey: .count)
        details = try values.decodeIfPresent([Details].self, forKey: .details)
    }

}

详细struct

struct Details : Codable {
    let unnecessaryDetails : String?
    let area : Area?

    enum CodingKeys: String, CodingKey {

        case unnecessaryDetails = "unnecessaryDetails"
        case area = "area"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        unnecessaryDetails = try values.decodeIfPresent(String.self, forKey: .unnecessaryDetails)
        area = try values.decodeIfPresent(Area.self, forKey: .area)
    }

}

区域struct

struct Area : Codable {
    let name : String?

    enum CodingKeys: String, CodingKey {

        case name = "name"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decodeIfPresent(String.self, forKey: .name)
    }

}

您甚至可以使用SwiftyJSON仅解析所需的字段。

您可以在这种情况下使用Codable 它将自动忽略您未在结构中定义的属性。 您的结构可以像这样:

struct Response: Codable {
    let result: String
    let count: Int
    let details: [Detail]
}

struct Detail: Codable {
    let area: Area
}

struct Area: Codable {
    let name: String
}

并解析:

let response = try? JSONDecoder().decode(Response.self, from: jsonData)

之后,您可以访问在结构中定义的任何属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM