Skip to content

Instantly share code, notes, and snippets.

@reckenrode
Created June 23, 2017 14:25
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save reckenrode/069e121371eb8db41231edfcd4bd14a8 to your computer and use it in GitHub Desktop.
Save reckenrode/069e121371eb8db41231edfcd4bd14a8 to your computer and use it in GitHub Desktop.
Decoding arbitrary JSON with the new Decoder in Swift 4
enum JSON: Decodable {
case bool(Bool)
case double(Double)
case string(String)
indirect case array([JSON])
indirect case dictionary([String: JSON])
init(from decoder: Decoder) throws {
if let container = try? decoder.container(keyedBy: JSONCodingKeys.self) {
self = JSON(from: container)
} else if let container = try? decoder.unkeyedContainer() {
self = JSON(from: container)
} else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: ""))
}
}
private init(from container: KeyedDecodingContainer<JSONCodingKeys>) {
var container = container
var dict: [String: JSON] = [:]
for key in container.allKeys {
if let value = try? container.decode(Bool.self, forKey: key) {
dict[key.stringValue] = .bool(value)
} else if let value = try? container.decode(Double.self, forKey: key) {
dict[key.stringValue] = .double(value)
} else if let value = try? container.decode(String.self, forKey: key) {
dict[key.stringValue] = .string(value)
} else if let value = try? container.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key) {
dict[key.stringValue] = JSON(from: value)
} else if let value = try? container.nestedUnkeyedContainer(forKey: key) {
dict[key.stringValue] = JSON(from: value)
}
}
self = .dictionary(dict)
}
private init(from container: UnkeyedDecodingContainer) {
var container = container
var arr: [JSON] = []
while !container.isAtEnd {
if let value = try? container.decode(Bool.self) {
arr.append(.bool(value))
} else if let value = try? container.decode(Double.self) {
arr.append(.double(value))
} else if let value = try? container.decode(String.self) {
arr.append(.string(value))
} else if let value = try? container.nestedContainer(keyedBy: JSONCodingKeys.self) {
arr.append(JSON(from: value))
} else if let value = try? container.nestedUnkeyedContainer() {
arr.append(JSON(from: value))
}
}
self = .array(arr)
}
}
struct JSONCodingKeys: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
self.init(stringValue: "\(intValue)")
self.intValue = intValue
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment