Skip to content

Instantly share code, notes, and snippets.

@pfandrade
Created February 12, 2020 15:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfandrade/ad4fc23c7847ba404d64b4ac1b405f49 to your computer and use it in GitHub Desktop.
Save pfandrade/ad4fc23c7847ba404d64b4ac1b405f49 to your computer and use it in GitHub Desktop.
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