Skip to content

Instantly share code, notes, and snippets.

@IanKeen
Last active March 3, 2022 00:57
Show Gist options
  • Save IanKeen/4403dba9253b7da165e3586c80a052b8 to your computer and use it in GitHub Desktop.
Save IanKeen/4403dba9253b7da165e3586c80a052b8 to your computer and use it in GitHub Desktop.
Skipping nested wrappers in json w/ Codable
extension KeyedDecodingContainer {
func decode<T: Decodable, Inner: CodingKey>(_ type: T.Type, forKey key: KeyedDecodingContainer.Key, innerKey: Inner) throws -> [T] {
var array = try nestedUnkeyedContainer(forKey: key)
var items: [T] = []
while !array.isAtEnd {
let container = try array.nestedContainer(keyedBy: Inner.self)
let item = try container.decode(T.self, forKey: innerKey)
items.append(item)
}
return items
}
func decodeIfPresent<T: Decodable, Inner: CodingKey>(_ type: T.Type, forKey key: KeyedDecodingContainer.Key, innerKey: Inner) throws -> [T]? {
guard contains(key) else { return nil }
return try decode(type, forKey: key, innerKey: innerKey)
}
}
extension KeyedEncodingContainer {
mutating func encode<T: Encodable, Inner: CodingKey>(_ value: [T], forKey key: KeyedEncodingContainer.Key, innerKey: Inner) throws {
var array = nestedUnkeyedContainer(forKey: key)
for item in value {
var container = array.nestedContainer(keyedBy: Inner.self)
try container.encode(item, forKey: innerKey)
}
}
mutating func encodeIfPresent<T: Encodable, Inner: CodingKey>(_ value: [T]?, forKey key: KeyedEncodingContainer.Key, innerKey: Inner) throws {
guard let value = value, !value.isEmpty else { return }
try encode(value, forKey: key, innerKey: innerKey)
}
}
struct Parent: Codable {
let items: [Item]
}
struct Item: Codable {
let name: String
}
extension Parent {
private enum CodingKeys: String, CodingKey {
case attachments
}
private enum AttachmentKeys: String, CodingKey {
case content
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.items = try container.decode(Item.self, forKey: .attachments, innerKey: AttachmentKeys.content)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(items, forKey: .attachments, innerKey: AttachmentKeys.content)
}
}
let json = """
{
"attachments": [
{
"content": {
"name": "foo"
}
},
{
"content": {
"name": "bar"
}
}
]
}
""".data(using: .utf8)!
do {
let object = try JSONDecoder().decode(Parent.self, from: json)
print(object.items)
let parent = Parent(items: [
Item(name: "foo"),
Item(name: "bar")
]
)
print(try String(data: JSONEncoder().encode(parent), encoding: .utf8)!)
} catch let error {
print(error)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment