My solution below:
import Cocoa
struct Spaceman: Codable {
var name: String
var race: String
}
struct Spaceship {
var name: String
var crew: [Spaceman]
enum CodingKeys: String, CodingKey {
case name = "spaceship_name"
case crew
}
}
struct EarthTransmission: Codable {
var name: String
var captain: Spaceman
var officer: Spaceman
enum CodingKeys: String, CodingKey {
case name
case captain
case officer
}
}
extension Spaceship: Encodable {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: EarthTransmission.CodingKeys.self)
try container.encode(name, forKey: .name)
// Assume index 0 is always captain, index 1 is always officer
try container.encode(crew[0], forKey: .captain)
try container.encode(crew[1], forKey: .officer)
}
}
extension Spaceship: Decodable {
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: EarthTransmission.CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
let captain = try values.decode(Spaceman.self, forKey: .captain)
let officer = try values.decode(Spaceman.self, forKey: .officer)
crew = [Spaceman]()
crew.append(captain)
crew.append(officer)
}
}
// Create JSON transmission from Earth
let earthTransmission = EarthTransmission(name: "USS Enterprise", captain: Spaceman(name: "Spock", race: "Human"), officer: Spaceman(name: "Worf", race: "Klingon"))
let earthEncoder = JSONEncoder()
let earthTransmissionData = try earthEncoder.encode(earthTransmission)
// Test the JSON string
if let earthTransmissionString = String(bytes: earthTransmissionData, encoding: .utf8) {
print(earthTransmissionString)
}
// Decoding Earth's transmission
let spaceshipDecoder = JSONDecoder()
let message = try spaceshipDecoder.decode(Spaceship.self, from: earthTransmissionData)
print(message)
/*
Output:
{"name":"USS Enterprise","captain":{"name":"Spock","race":"Human"},"officer":{"name":"Worf","race":"Klingon"}}
Spaceship(name: "USS Enterprise", crew: [__lldb_expr_18.Spaceman(name: "Spock", race: "Human"), __lldb_expr_18.Spaceman(name: "Worf", race: "Klingon")])
*/