Last active
June 13, 2019 15:04
-
-
Save rnapier/7e2de4ea2921039f2726cec064f28949 to your computer and use it in GitHub Desktop.
Decode based on a type field
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 | |
/// 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