2

I have a json response like this

{
  "name":"test",
  "params":{ 
    "param1":"testA", 
    "param2":4055, 
    "param3":9593.34959, 
    "question":"is this is a test?", 
    "anything":"testing?", 
    "random":true
   },
  "price":103.3
}

My codable struct looks like this

struct:Codable {
    var name:String 
    var params:[String:String]?
    var price:Double
}

I have set params to optional because sometimes there are no params but a lot of times there are and codable has an issue because I don't know what types the values in the params dictionary are. I don't even know what the keys are sometimes. I just want to parse them as a dictionary of keys and values with values of type Bool, Int, Double, or String. so a dict like this

let params = ["paramA":1, "param2":"test", "param3":true]

or in the case of the above json this:

let params = ["param1":"testA", "param2":4055, "param3": 9593.34959, "question":"is this is a test?", "anything":"testing?", "random":true]

I am pretty sure I have to create a custom decoder but not exactly sure how to do it.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Nevin Jethmalani
  • 2,726
  • 4
  • 23
  • 58

1 Answers1

0

In your case it's easier to decode json manually like so:

public enum SerializationError: Error {
   case wrongRootElement(String)
   case missing(String)
   case invalid(String, Any)
}
struct YourStruct {
   var name:String
   var params:[String: String]?
   var price:Double
}

extension YourStruct {
   public init(json: Any) throws {
       guard let jsonDict = json as? [String: Any] else {
           throw SerializationError.wrongRootElement("Expected json dictionary not \(json)")
       }
       guard let name = jsonDict["name"] as? String else {
           throw SerializationError.missing("name")
       }
       let params = jsonDict["params"] as? [String: Any]
       let paramsStrs = params?.reduce(into: [String: String]()) { (result, keyValue)  in
           result[keyValue.key] = String(describing: keyValue.value)
       }
       guard let price = jsonDict["price"] as? Double else {
           throw SerializationError.missing("price")
       }
       self.init(name: name, params: paramsStrs, price: price)
    }
}

let anyYourStruct = try? JSONSerialization.jsonObject(with: jsonData, options: [])
let yourStruct = try? YourStruct(json: anyYourStruct)
Andrey Volobuev
  • 862
  • 8
  • 11
  • I figured as much and went ahead using swiftyjson to do something similar to what you have written here. Thanks for your help! – Nevin Jethmalani Mar 08 '18 at 18:50
  • One alternative way is ```if let stringValue = try? container.decode(String.self, forkey: .abc) { } else if let intValue = try? container.decode(Int.self, forkey: .abc) ...``` – Rajesh Budhiraja Dec 03 '21 at 08:18