In trying to serialize an array of float3 objects with the basic JSONEncoder, it\'s revealed that float3 does not conform to the Codable protocol, so this cannot be done.
You can solve the compiler error by instead of trying to directly assign the decoded values to the fields of your type, storing the decoded values in local variables, then calling a designated initializer of float3.
As Rob mentions in his answer, the cause of the issue has to do with x, y and z being computed properties rather than stored ones, so they cannot be directly written during initialization.
extension float3: Codable {
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let x = try values.decode(Float.self, forKey: .x)
let y = try values.decode(Float.self, forKey: .y)
let z = try values.decode(Float.self, forKey: .z)
self.init(x, y, z)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(x, forKey: .x)
try container.encode(y, forKey: .y)
try container.encode(z, forKey: .z)
}
private enum CodingKeys: String, CodingKey {
case x,y,z
}
}
You can test both encoding and decoding in a Playground using below code:
let vector = float3(3, 2.4, 1)
do {
let encodedVector = try JSONEncoder().encode(vector)
let jsonVector = String(data: encodedVector, encoding: .utf8) //"{"x":3,"y":2.4000000953674316,"z":1}"
let decodedVector = try JSONDecoder().decode(float3.self, from: encodedVector) //float3(3.0, 2.4, 1.0)
} catch {
print(error)
}
If you prefer more concise code, the init(from decoder:) method can be shortened to:
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
try self.init(values.decode(Float.self, forKey: .x), values.decode(Float.self, forKey: .y), values.decode(Float.self, forKey: .z))
}