Skip to content

Instantly share code, notes, and snippets.

@rnapier rnapier/TypeCoder.swift
Last active Jun 13, 2019

Embed
What would you like to do?
Decode based on a type field
import Foundation
/// Simple example of decoding different values based on a "type" field
let json = Data("""
[{
"type": "user",
"name": "Alice"
},
{
"type": "document",
"path": "/etc/passwd"
}
]
""".utf8)
struct User: Codable {
let name: String
}
struct Document: Codable {
let path: String
}
enum Item {
case user(User)
case document(Document)
}
extension Item: Codable {
enum CodingKeys: CodingKey {
case type
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(String.self, forKey: .type)
// The important point here is that you can extract a second container with a different
// CodingKey from the same decoder.
switch type {
case "user": self = .user(try User(from: decoder))
case "document": self = .document(try Document(from: decoder))
default: throw DecodingError.dataCorruptedError(forKey: .type, in: container,
debugDescription: "Unknown type")
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .user(let user):
// And similarly, you can just keep encoding other stuff into the current encoder.
try container.encode("user", forKey: .type)
try user.encode(to: encoder)
case .document(let document):
try container.encode("document", forKey: .type)
try document.encode(to: encoder)
}
}
}
let items = try JSONDecoder().decode([Item].self, from: json)
print(items)
let output = try JSONEncoder().encode(items)
print(String(data: output, encoding: .utf8)!)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.