AnyDecodable
import Foundation | |
struct AnyDecodable: Decodable { | |
static let supportedTypes = CodingUserInfoKey(rawValue: "SupportedTypes")! | |
enum Errors: Error { | |
case missingSupportedTypesList | |
case unknownType | |
} | |
typealias DecodableValue = Any & Decodable | |
let value: DecodableValue | |
init(from decoder: Decoder) throws { | |
guard let supportedTypes = decoder.userInfo[AnyDecodable.supportedTypes] as? [Any.Type] else { | |
throw Errors.missingSupportedTypesList | |
} | |
let decodableTypes = supportedTypes.compactMap { $0 as? Decodable.Type } | |
var decodedValue: DecodableValue? | |
for decodableValueType in decodableTypes { | |
do { | |
decodedValue = try decodableValueType.init(from: decoder) | |
break | |
} catch { | |
continue | |
} | |
} | |
guard let v = decodedValue else { | |
throw Errors.unknownType | |
} | |
value = v | |
} | |
} | |
struct Person: Codable { | |
let name: String | |
} | |
struct Dog: Codable { | |
let breed: String | |
} | |
let decoder = JSONDecoder() | |
decoder.userInfo[AnyDecodable.supportedTypes] = [Person.self, Dog.self] | |
let p = try decoder.decode(AnyDecodable.self, from: "{\"name\":\"Joe\"}".data(using: .utf8)!).value | |
print(p) // Person(name: "Joe") | |
let d = try decoder.decode(AnyDecodable.self, from: "{\"breed\":\"Caniche\"}".data(using: .utf8)!).value | |
print(d) // Dog(breed: "Caniche") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment