Last active
May 9, 2016 02:40
-
-
Save tomquist/2f53fcc6d98c70f0a79a120e8a9203f2 to your computer and use it in GitHub Desktop.
Decoding heterogeneous array in swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
struct User { | |
let name: String | |
let age: Int | |
} | |
struct Car { | |
let color: String | |
} | |
enum Entry { | |
case user(User) | |
case car(Car) | |
} | |
typealias Json = Any | |
typealias JsonDict = [String: Json] | |
protocol Decodable { | |
init(json: Json) throws | |
} | |
enum JsonMappingError: ErrorType { | |
case WrongType | |
case MissingField | |
case UnknownType | |
} | |
extension User: Decodable { | |
init(json: Json) throws { | |
guard let dict = json as? JsonDict else { | |
throw JsonMappingError.WrongType | |
} | |
guard let name = dict["name"] as? String, | |
age = dict["age"] as? Int else { | |
throw JsonMappingError.MissingField | |
} | |
self.name = name | |
self.age = age | |
} | |
} | |
extension Car: Decodable { | |
init(json: Json) throws { | |
guard let dict = json as? JsonDict else { | |
throw JsonMappingError.WrongType | |
} | |
guard let color = dict["color"] as? String else { | |
throw JsonMappingError.MissingField | |
} | |
self.color = color | |
} | |
} | |
protocol TypedDecodable: Decodable { | |
init(type: String, dict: JsonDict) throws | |
} | |
extension TypedDecodable { | |
init(json: Json) throws { | |
guard let dict = json as? JsonDict else { | |
throw JsonMappingError.WrongType | |
} | |
guard let type = dict["type"] as? String else { | |
throw JsonMappingError.MissingField | |
} | |
try self.init(type: type, dict: dict) | |
} | |
} | |
protocol EnumTypedDecodable: TypedDecodable { | |
static var typeMap: [String: (Json throws -> Self)] { get } | |
} | |
extension EnumTypedDecodable { | |
init(type: String, dict: JsonDict) throws { | |
guard let creator = Self.typeMap[type] else { | |
throw JsonMappingError.UnknownType | |
} | |
self = try creator(dict) | |
} | |
} | |
extension Entry: EnumTypedDecodable { | |
static var typeMap: [String: (Json throws -> Entry)] = [ | |
"user": { .user(try User(json: $0)) }, | |
"car": { .car(try Car(json: $0)) }, | |
] | |
} | |
let json: [JsonDict] = [ | |
["type": "car", "color": "blue"], | |
["type": "user", "name": "John", "age": 30] | |
] | |
try json.map(Entry.init) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment