Skip to content

Instantly share code, notes, and snippets.

@DanielCardonaRojas
Created December 14, 2022 15:37
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 DanielCardonaRojas/c3bda98a172dde07918c25bc917cd7ea to your computer and use it in GitHub Desktop.
Save DanielCardonaRojas/c3bda98a172dde07918c25bc917cd7ea to your computer and use it in GitHub Desktop.
Reach deeply nested object without having to create all intermediate CodingKeys
class Nested<T: Decodable>: Decodable
{
let value: T
enum DecodeError: Error
{
case nestedKeyPathNotConfigure
case keyNotConfigured
}
private struct DynamicCodingKeys: CodingKey
{
// Use for string-keyed dictionary
var stringValue: String
init?(stringValue: String)
{
self.stringValue = stringValue
}
// Use for integer-keyed dictionary
var intValue: Int?
init?(intValue _: Int)
{
// We are not using this, thus just return nil
return nil
}
}
required init(from decoder: Decoder) throws
{
guard let nestedKeyValueKeyPath = decoder.userInfo[.nestedKeyUserInfoKey] as? [String]
else
{
throw DecodeError.nestedKeyPathNotConfigure
}
guard !nestedKeyValueKeyPath.isEmpty
else
{
value = try decoder.singleValueContainer().decode(T.self)
return
}
let keyPathLength = nestedKeyValueKeyPath.count
var container: KeyedDecodingContainer<DynamicCodingKeys> = try decoder.container(keyedBy: DynamicCodingKeys.self)
for k in 0 ..< (keyPathLength - 1)
{
let key = nestedKeyValueKeyPath[k]
let codingKey = DynamicCodingKeys(stringValue: key)!
container = try container.nestedContainer(keyedBy: DynamicCodingKeys.self, forKey: codingKey)
}
let lastKey = nestedKeyValueKeyPath[keyPathLength - 1]
value = try container.decode(T.self, forKey: DynamicCodingKeys(stringValue: lastKey)!)
}
}
public extension CodingUserInfoKey
{
static let nestedKeyUserInfoKey = CodingUserInfoKey(rawValue: "Nested.Key")!
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment