Getting JSONDecoder, Decodable String or Integer

52 Views Asked by At

I'm trying Decodable from JSON result. Sometimes the result is Int/String. This code works, return Int(val) or String(val), but how to extract only val without Int(val) and String(val)?

enum StringOrInt: Decodable {
   case string(String)
   case int(Int)
        
   init(from decoder: Decoder) throws {
       if let int = try? decoder.singleValueContainer().decode(Int.self) {
            self = .int(int)
            return
       }
       if let string = try? decoder.singleValueContainer().decode(String.self) {
           self = .string(string)
           return
       }
            
        throw Error.couldNotFindStringOrInt
    }
    enum Error: Swift.Error {
        case couldNotFindStringOrInt
    }
}
    
struct properties: Decodable {
   let name: StringOrInt
}

let propData = feature.properties!
let resData = try? JSONDecoder.init().decode(properties.self, from: propData)
print(resData.name) 

result: string("str") or int(0), I need always "str" or "0".

1

There are 1 best solutions below

0
Leo Dabus On BEST ANSWER

You can use something called property wrapper. You can try to decode a String and if throws a type mismatch decoding error you can catch that error and try to decode your integer and store it as a string. This way it will only try to decode it again if the error is a type mismatch otherwise it will throw the error right away:

@propertyWrapper
struct StringOrInt: Decodable {

    var wrappedValue: String

    init(wrappedValue: String) {
        self.wrappedValue = wrappedValue
    }

    public init(from decoder: Decoder) throws {
        do {
            wrappedValue = try decoder.singleValueContainer().decode(String.self)
        } catch DecodingError.typeMismatch {
            wrappedValue = try decoder.singleValueContainer().decode(Int.self).string
        }
    }
}

extension LosslessStringConvertible {
    var string: String { .init(self) }
}

Usage:

struct Properties: Decodable {
    @StringOrInt var name: String
}