Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using codable with value that is sometimes an Int and other times a String

I have an API that will sometimes return a specific key value (in this case id) in the JSON as an Int and other times it will return that same key value as a String. How do I use codable to parse that JSON?

struct GeneralProduct: Codable {     var price: Double!     var id: String?     var name: String!      private enum CodingKeys: String, CodingKey {         case price = "p"         case id = "i"         case name = "n"     }      init(price: Double? = nil, id: String? = nil, name: String? = nil) {         self.price = price         self.id = id         self.name = name     } } 

I keep getting this error message: Expected to decode String but found a number instead. The reason that it returns a number is because the id field is empty and when the id field is empty it defaults to returning 0 as an ID which codable identifies as a number. I can basically ignore the ID key but codable does not give me the option to ignore it to my knowledge. What would be the best way to handle this?

Here is the JSON. It is super simple

Working

{   "p":2.12,   "i":"3k3mkfnk3",   "n":"Blue Shirt" } 

Error - because there is no id in the system, it returns 0 as a default which codable obviously sees as a number opposed to string.

{   "p":2.19,   "i":0,   "n":"Black Shirt" } 
like image 539
Nevin Jethmalani Avatar asked Dec 22 '17 04:12

Nevin Jethmalani


People also ask

Is string a Codable Swift?

Remember, Swift's String , Int , and Bool are all Codable ! Earlier I wrote that your structs, enums, and classes can conform to Codable . Swift can generate the code needed to extract data to populate a struct's properties from JSON data as long as all properties conform to Codable .

Can a class conform to Codable?

If all the properties of a type already conform to Codable , then the type itself can conform to Codable with no extra work – Swift will synthesize the code required to archive and unarchive your type as needed.

What is Codable used for?

A type that can be used as a key for encoding and decoding. A type that can be converted to and from a coding key. A user-defined key for providing context during encoding and decoding.

What is Codable and Decodable?

typealias Codable = Decodable & Encodable. Decodable protocol Decodable : A type that can decode itself from an external representation (bytes to object) Encodable protocol Encodable : A type that can encode itself to an external representation. ( object to bytes) Codable = both encoding and decoding.


1 Answers

struct GeneralProduct: Codable {     var price: Double?     var id: String?     var name: String?     private enum CodingKeys: String, CodingKey {         case price = "p", id = "i", name = "n"     }     init(price: Double? = nil, id: String? = nil, name: String? = nil) {         self.price = price         self.id = id         self.name = name     }     init(from decoder: Decoder) throws {         let container = try decoder.container(keyedBy: CodingKeys.self)         price = try container.decode(Double.self, forKey: .price)         name = try container.decode(String.self, forKey: .name)         do {             id = try String(container.decode(Int.self, forKey: .id))         } catch DecodingError.typeMismatch {             id = try container.decode(String.self, forKey: .id)         }     } } 

let json1 = """ { "p":2.12, "i":"3k3mkfnk3", "n":"Blue Shirt" } """  let json2 = """ { "p":2.12, "i":0, "n":"Blue Shirt" } """ 

do {     let product = try JSONDecoder().decode(GeneralProduct.self, from: Data(json2.utf8))     print(product.price ?? "nil")     print(product.id ?? "nil")     print(product.name ?? "nil") } catch {     print(error) } 

edit/update:

You can also simply assign nil to your id when your api returns 0:

do {     let value = try container.decode(Int.self, forKey: .id)     id = value == 0 ? nil : String(value) } catch DecodingError.typeMismatch {     id = try container.decode(String.self, forKey: .id) } 
like image 76
Leo Dabus Avatar answered Sep 20 '22 14:09

Leo Dabus