简体   繁体   中英

Elegant solutions to decoding a JSON nested array in swift using decodable

Currently working with an API, and while I have successfully gotten it to decode the full result, I am only interested in the Entities/identifier portion. While I have gotten it working and get what I want/need I feel like this could be done better and more elegant and maybe in a single step. Any insight/suggestions appreciated.

JSON returned from API:

 {
    "count": 4596,
    "entities": [
        {
            "facet_ids": [
                "contact",
                "siftery",
                "investor",
                "ipqwery",
                "aberdeen",
                "apptopia",
                "semrush",
                "company",
                "rank",
                "builtwith",
                "bombora",
                "key_event"
            ],
            "identifier": {
                "uuid": "468bef9f-2f50-590e-6e78-62e3adb05aa1",
                "value": "Citi",
                "image_id": "v1417152861/pdgwqt8ddecult5ktvdf.jpg",
                "permalink": "citigroup",
                "entity_def_id": "organization"
            },
            "short_description": "Citigroup is a diversified financial services holding company that provides various financial products and services."
        },
        {
            "facet_ids": [
                "contact",
                "siftery",
                "investor",
                "apptopia",
                "semrush",
                "company",
                "rank",
                "builtwith",
                "key_event"
            ],
            "identifier": {
                "uuid": "031a344b-c2b9-e60b-d950-1ae062026fde",
                "value": "Citi",
                "image_id": "yzlzhjqpparamrswaqa1",
                "permalink": "citi-2",
                "entity_def_id": "organization"
            },
            "short_description": "CITi is an NPO supporting the ICT sector in Western Cape."
        },
        {
            "facet_ids": [
                "contact",
                "siftery",
                "semrush",
                "company",
                "rank",
                "builtwith",
                "bombora"
            ],
            "identifier": {
                "uuid": "7ce45379-957c-49c5-bca2-c9ffd521f7da",
                "value": "CITI",
                "image_id": "qbkqndm7d0wgbogxjcrs",
                "permalink": "citi-f7da",
                "entity_def_id": "organization"
            },
            "short_description": "CITI trusted gateway to project-based change expertise that major organisations need to thrive, change and innovate."
        }
    ]
}

Structs:

    struct Entity: Decodable, Identifiable
{
    var id: String
    var companyName: String
    var permalink: String
    var imageID: String
    
    init(from entity: Entities.Entity) throws
    {
        self.id = entity.identifier?.uuid ?? ""
        self.companyName = entity.identifier?.value ?? ""
        self.permalink = entity.identifier?.permalink ?? ""
        self.imageID = entity.identifier?.image_id ?? ""
    }
    
}

 struct Entities: Decodable
    {
    var count:Int?
    var entities: [Entity]?
    
    struct Entity: Decodable
    {
        var facet_ids:[String]?
        var identifier:Identifier?
        var short_description:String?
    }
    
    struct Identifier:Decodable
    {
        var permalink:String?
        var value:String?
        var image_id:String?
        var entity_def_id:String?
        var uuid:String?
    }
}

Call to decode:

        if let data = data{
        do {
            let businessEntities = try decoder.decode(Entities.self, from: data)
            
            let entities:[Entity] = try businessEntities.entities!.compactMap{
                entity in
                do
                {
                    return try Entity(from: entity)
                }
            }

Thinking you are just interested in the Entities/identifier, you can simplify your model. Here's an example:

typealias Entities = [Entitie]

struct Entitie: Codable {
    let facetIDS: [String]
    let identifier: Identifier
    let shortDescription: String

    enum CodingKeys: String, CodingKey {
        case facetIDS = "facet_ids"
        case identifier
        case shortDescription = "short_description"
    }
}

struct Identifier: Codable {
    let uuid, value, imageID, permalink: String
    let entityDefID: String

    enum CodingKeys: String, CodingKey {
        case uuid, value
        case imageID = "image_id"
        case permalink
        case entityDefID = "entity_def_id"
    }
}

You can access entities object and decode it like this:

guard let data = data,
      let jsonDict = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
      let entitiesObj = jsonDict["entities"] else { return }

do {
    let entitiesData = try JSONSerialization.data(withJSONObject: entitiesObj)
    let result = try JSONDecoder().decode(Entities.self, from: entitiesData)
} catch {
    print(error.localizedDescription)
}

Obs: I created the CodingKeys because I use camelCase in my projects, you can left it in snake_case just remember to replace variables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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