Skip to content

Instantly share code, notes, and snippets.

@edwardaux
Created June 17, 2017 22:15
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 edwardaux/102592ad5175862cda81256615eaf74c to your computer and use it in GitHub Desktop.
Save edwardaux/102592ad5175862cda81256615eaf74c to your computer and use it in GitHub Desktop.
//: Playground - noun: a place where people can play
import Foundation
class DecodableCache<Key,Value> where Key : Hashable {
private var values: [Key:Value] = [:]
subscript(index: Key) -> Value? {
get {
return values[index]
}
set(newValue) {
values[index] = newValue
}
}
}
extension Decoder {
private var personCache: DecodableCache<Int,Person> {
var personCacheKey = "personCache"
if let cache = objc_getAssociatedObject(self, &personCacheKey) as? DecodableCache<Int,Person> {
return cache
}
else {
let cache = DecodableCache<Int,Person>()
objc_setAssociatedObject(self, &personCacheKey, cache, .OBJC_ASSOCIATION_RETAIN)
return cache
}
}
func nestedPerson(container: KeyedDecodingContainer<Car.CodingKeys>, forKey key: Car.CodingKeys) throws -> Person {
let personContainer = try container.nestedContainer(keyedBy: Car.PersonKeys.self, forKey: key)
let personId = try personContainer.decode(Int.self, forKey: .identifier)
if let cachedPerson = personCache[personId] {
return cachedPerson
}
let decodedPerson = try container.decode(Person.self, forKey: key)
personCache[personId] = decodedPerson
return decodedPerson
}
}
class Person : Codable {
let identifier: Int
init(identifier: Int) {
self.identifier = identifier
}
}
struct Car : Codable {
let owner: Person
let driver: Person
enum CodingKeys: String, CodingKey {
case owner
case driver
}
enum PersonKeys: String, CodingKey {
case identifier
}
public init(owner: Person, driver: Person) {
self.owner = owner
self.driver = driver
}
public init(from decoder: Decoder) throws {
let myContainer = try decoder.container(keyedBy: Car.CodingKeys.self)
self.owner = try decoder.nestedPerson(container: myContainer, forKey: .owner)
self.driver = try decoder.nestedPerson(container: myContainer, forKey: .driver)
}
}
let kate = Person(identifier: 200)
let car = Car(owner: kate, driver: kate)
let data = try JSONEncoder().encode(car)
let json = String(data: data, encoding: .utf8)!
let car2 = try JSONDecoder().decode(Car.self, from: data)
print(Unmanaged.passUnretained(car2.owner).toOpaque().debugDescription)
print(Unmanaged.passUnretained(car2.driver).toOpaque().debugDescription)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment