-
-
Save hamishknight/6840442a3195da64bb01004f6bc6c31e to your computer and use it in GitHub Desktop.
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 AnyCodingKey : CodingKey { | |
let stringValue: String | |
let intValue: Int? | |
init(_ base: CodingKey) { | |
self.stringValue = base.stringValue | |
self.intValue = base.intValue | |
} | |
init?(intValue: Int) { | |
self.intValue = intValue | |
self.stringValue = String(intValue) | |
} | |
init?(stringValue: String) { | |
self.stringValue = stringValue | |
self.intValue = Int(stringValue) | |
} | |
} | |
extension JSONDecoder { | |
private static let rootKeyPathKey = CodingUserInfoKey(rawValue: "rootKeyPath")! | |
private struct KeyPathDecodable<Value : Decodable> : Decodable { | |
let value: Value | |
init(from decoder: Decoder) throws { | |
let keyPath = decoder.userInfo[JSONDecoder.rootKeyPathKey] as! [AnyCodingKey] | |
var container = try decoder.container(keyedBy: AnyCodingKey.self) | |
for key in keyPath.dropLast() { | |
container = try container.nestedContainer(keyedBy: AnyCodingKey.self, forKey: key) | |
} | |
self.value = try container.decode(Value.self, forKey: keyPath.last!) | |
} | |
} | |
func decode<T : Decodable>(_ type: T.Type, rootKeyPath: [AnyCodingKey], from data: Data) throws -> T { | |
userInfo[JSONDecoder.rootKeyPathKey] = rootKeyPath | |
return try decode(KeyPathDecodable<T>.self, from: data).value | |
} | |
} | |
struct Address : Codable { | |
var street: String | |
var zip: String | |
var city: String | |
var state: String | |
} | |
let jsonString = """ | |
{ | |
"foo": "hello world", | |
"house": { | |
"bar": 67.8, | |
"address": { | |
"state": "California", | |
"street": "Apple Bay Street", | |
"zip": "94608", | |
"city": "Emeryville" | |
} | |
} | |
} | |
""" | |
enum PersonToAddressCodingKeys : CodingKey { | |
case house, address | |
} | |
let jsonData = jsonString.data(using: .utf8)! | |
do { | |
print(try JSONDecoder().decode(Address.self, rootKeyPath: [PersonToAddressCodingKeys.house, .address].map(AnyCodingKey.init), from: jsonData)) | |
} catch { | |
print(error) | |
} | |
// Address(street: "Apple Bay Street", zip: "94608", city: "Emeryville", state: "California") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment