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".
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
}