0

I make HTTP requests to a server and I receive JSON documents. I have the following structure to decode the JSON:

struct DocumenJSON: Codable {
    let code: Int?
    let description: String?
    let value: Value?
}

The problem is that making a request "A" I receive an Object value and making the request "B" an Array of Value, so the struct should be the following:

struct DocumenJSONArray: Codable {
    let code: Int?
    let description: String?
    let value: [Value]?
}

How can I implement this in swift 4 without duplicate code?

            } catch let jsonErr {
                print("Error serializing json:", jsonErr)
                do {
                document = try JSONDecoder().decode(DocumenJSON.self, from: data)
                user = User.init(password: "", email: document?.value?.email ?? "Empty", givenNames: document?.value?.nickname ?? "Empty", familyName: document?.value?.lastname ?? "Empty", phone: document?.value?.nickname   ?? "Empty")
                } catch let jsonErr2 {
                    print("Error serializing json2:", jsonErr2)
                }
            }
scd
  • 212
  • 4
  • 13
  • 1
    You have to write a custom initializer which handle the cases. – vadian Aug 07 '18 at 09:42
  • 1
    decodeIfpresent inside init – Shehata Gamal Aug 07 '18 at 09:43
  • I don't know what you mean @vadian . Could you show me an example? – scd Aug 07 '18 at 09:46
  • 1
    Same question seen there: https://stackoverflow.com/questions/51711891/swift-how-to-decode-result-from-api-which-is-being-returned-as-a-string-or-as-a ? – Larme Aug 07 '18 at 09:47
  • Put `decode(String.self...` in an extra `do - catch` block. In the `catch` branch decode `[String]` – vadian Aug 07 '18 at 09:48
  • @Sh_Khan I have never seen something related with decodelfpresent. Do you have some documentation about that? – scd Aug 07 '18 at 09:48
  • 1
    @Sh_Khan `decodeIfPresent` has no effect as the key is present in both cases. – vadian Aug 07 '18 at 09:49
  • @vadian You can see now in the question the code I have implemented, but I don't know how to change de DocumentJSON to set the attribute Value as an array. – scd Aug 07 '18 at 10:05
  • No you have to add CodingKeys and a custom initializer in the `DocumenJSON` struct to be able to use only one struct. And don't declare all properties carelessly as optional. Use optionals only if a key can be missing. – vadian Aug 07 '18 at 10:12

1 Answers1

0

A possible solution is to use a single struct, for instance:

extension DocumenJSON: Decodable {
    enum CodingKeys: String, CodingKey {
        case code
        case description
        case valueAsObject
        case valueAsArray
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        code = try values.decodeIfPresent(Int.self, forKey: .code)
        description = try values.decodeIfPresent(String.self, forKey: .description)
        valueAsObject = try values.decodeIfPresent(Value.self, forKey: .valueAsObject)
        valueAsArray = try values.decodeIfPresent(Array.self, forKey: .valueAsArray)
    }
}

Now, whenever you call DocumenJSON just check for each property which valueAsObject or valueAsArray is nil.

Probably not the prettiest solution but at least you're not repeating structs.

Alexander Perechnev
  • 2,797
  • 3
  • 21
  • 35
jpcarreira
  • 76
  • 5