DookieMan
DookieMan

Reputation: 1044

How to use Swift 4 Decodable when JSON root in mutliple array's with different properties

So I've been using Swift 4's new Decodable protocol and it's been great, but now I've come across an instance that I can't find an answer. I'm trying to use decodable to parse the Reddit Comments API response. Here is a quick example. (Note this isn't the full response, just something quick for example)

Here is a quick example of my problem. If you look at the "data" key inside of "children" the dictionaries contain different data. Is there a way to have two different JSON objects in the children array depending on what contents they have or based on their position in the array?

[{
    "kind": "Listing",
    "data": {
        "modhash": "kskppiefdzafc020177a3995ccd7f13b4ba0a8ca70e691a510",
        "whitelist_status": "all_ads",
        "children": [{
            "kind": "t3",
            "data": {
                "domain": "i.redd.it",
                "approved_at_utc": null,
                "mod_reason_by": null,
                "selftext_html": "Hello world!!!"
            }
        }]
    }
}, {
    "kind": "Listing",
    "data": {
        "modhash": "kskppiefdzafc020177a3995ccd7f13b4ba0a8ca70e691a510",
        "whitelist_status": "all_ads",
        "children": [{
            "kind": "t3",
            "data": {
                "domain": "i.redd.it",
                "approved_at_utc": null,
                "author": null,
                "body": "Hello world"
            }
        }]
    }

}]

Essentially what I'm curious is possible is this....

public struct CommentRoot: Decodable {
    struct Datafield: Decodable {
        let modhash: String
        let whitelist_status: String
        let children: [Comment]? // <------ Can be 1 of 2 types of comment that vary.
        let after: String?
        let before: String?
    }
    let data: Datafield
    let kind: String
}

Upvotes: 2

Views: 522

Answers (1)

Joyal Clifford
Joyal Clifford

Reputation: 1212

I hop it will help you

import Foundation

struct Children : Decodable {

    let data : DataInfo?
    let kind : String?


    enum CodingKeys: String, CodingKey {
        case data
        case kind = "kind"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        data = try DataInfo(from: decoder)
        kind = try values.decodeIfPresent(String.self, forKey: .kind)
    }


}

       struct DataInfo : Decodable {

        let approvedAtUtc : String?
        let author : String?
        let body : String?
        let domain : String?
        let children : [Children]?
        let modhash : String?
        let whitelistStatus : String?


        enum CodingKeys: String, CodingKey {
            case approvedAtUtc = "approved_at_utc"
            case author = "author"
            case body = "body"
            case domain = "domain"
            case children = "children"
            case modhash = "modhash"
            case whitelistStatus = "whitelist_status"
        }
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            approvedAtUtc = try values.decodeIfPresent(String.self, forKey: .approvedAtUtc)
            author = try values.decodeIfPresent(String.self, forKey: .author)
            body = try values.decodeIfPresent(String.self, forKey: .body)
            domain = try values.decodeIfPresent(String.self, forKey: .domain)
            children = try values.decodeIfPresent([Children].self, forKey: .children)
            modhash = try values.decodeIfPresent(String.self, forKey: .modhash)
            whitelistStatus = try values.decodeIfPresent(String.self, forKey: .whitelistStatus)
        }


    }

Upvotes: 1

Related Questions