Adnan Khan
Adnan Khan

Reputation: 25

Managing Dynamic Keys in response through Codable Protocol

I need to make the codable model for the dynamic keys of dictionary coming from response below is the response I'm getting.

{ 
"data" : [
             {
               "desc1" : null,
               "file1" : "uploads\/posts\/Aug-2021\/1629271422310452767"
             },
             {
               "desc2" : "hello",
               "file2" : "uploads\/posts\/Aug-2021\/162927142279356160WhatsApp+Image+2021-07-02+at+12.09.14+PM.jpeg"
             }
         ],
"status" : "success"
}

This desc1 and file1 is dynamic till like file1, file2 and so on, I need to have codable model for that below is my model that is not supportive.

struct ListModel: Codable {
    public var data: [data]?
}
struct data: Codable {
   let file : String?
   let desc : String?
}

Anything support by codable protocol for that. Thanks in Advance.

Upvotes: 2

Views: 160

Answers (1)

Leo Dabus
Leo Dabus

Reputation: 236508

You need a custom initializer. Of course this will only work if your json will always come formatted as described:

struct File {
    var file: String? = ""
    var desc: String? = ""
}

struct Response {
    let files: [File]
    let status: String
    enum CodingKeys: String, CodingKey {
        case files = "data", status
    }
}

extension Response: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.status = try container.decode(String.self, forKey: .status)
        let elements = try container.decode([[String: String?]].self, forKey: .files)
        self.files = elements.reduce(into: []) {
            var file = File()
            for (key, value) in $1 {
                if key.hasPrefix("file") {
                    file.file = value
                } else if key.hasPrefix("desc") {
                    file.desc = value
                }
            }
            $0.append(file)
        }
    }
}

Playground testing:

let json = """
{
    "data" : [
                 {
                   "desc1" : null,
                   "file1" : "uploads/posts/Aug-2021/1629271422310452767"
                 },
                 {
                   "desc2" : "hello",
                   "file2" : "uploads/posts/Aug-2021/162927142279356160WhatsApp+Image+2021-07-02+at+12.09.14+PM.jpeg"
                 }
             ],
    "status" : "success"
}
"""

do {
    let response = try JSONDecoder().decode(Response.self, from: Data(json.utf8))
    print(response)
} catch {
    print(error)
}

This will print:

Response(files: [File(file: Optional("uploads/posts/Aug-2021/1629271422310452767"), desc: nil), File(file: Optional("uploads/posts/Aug-2021/162927142279356160WhatsApp+Image+2021-07-02+at+12.09.14+PM.jpeg"), desc: Optional("hello"))], status: "success")

Upvotes: 2

Related Questions