Есть ли способ переопределить реализацию Codable для структуры?
Код, который нельзя изменить:
struct obj1 : Codable {
var values:[Int]
...
}
Желаемый JSON:
{ "x": 1, "y": 2, "z": 3 }
Это не работает:
extension obj1 {
init(from decoder: Decoder) throws {
//This is never called
}
func encode(to encoder: Encoder) throws {
//This is never called
}
}
Предыстория:
Я сейчас портирую существующее приложение на iOS и конвертирую его в Swift из смеси C ++ и Objective- C. Это приложение использует Metal для создания 3D-графики и поэтому широко использует математические конструкции, такие как Vector, Matrix, Quaternion и т. Д. c.
В начале проекта я решил использовать для них библиотеку simd от Apple. различные типы. Я дал им псевдонимы, соответствующие объектам, которые у нас уже есть, чтобы облегчить перенос, и расширения для добавления различных функций, которые не были встроены. Все это отлично работает.
Теперь я нахожусь в той точке, где мне нужно чтобы иметь возможность преобразовать эти типы в / из JSON, и я столкнулся с проблемой. Структуры simd уже поддерживают Codable, но они используют формат, отличный от того, который мне нужно поддерживать. Поскольку simd использует структуры, я не могу получить от него собственное определение init(from)
и encode
. Также кажется, что я тоже не могу поместить свое собственное определение в расширение (компилятор не жалуется, но мои версии тоже не вызываются).
В настоящее время у меня это работает с использованием структуры оболочка (ie, Vector3Codable). Однако это означает, что любой из моих объектов, которые имеют эти члены simd, также должен предоставлять пользовательские реализации Codable, вместо этого используя поддержку по умолчанию, которую добавляет компилятор.
Я бы предпочел придерживаться simd, если это возможно, поскольку в отличие от предоставления моей собственной реализации для всего.
Изменить. Похоже, что мой упрощенный пример кода действительно работает (ох!). Вот фактический код, который не работает. Судя по всему, проблема сложнее, чем я думал изначально.
typealias Vector3 = SIMD3<Float>
extension Vector3 {
enum CodingKeys: String, CodingKey {
case x
case y
case z
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let x = try container.decodeIfPresent(Float.self, forKey: .x) ?? 0.0
let y = try container.decodeIfPresent(Float.self, forKey: .y) ?? 0.0
let z = try container.decodeIfPresent(Float.self, forKey: .z) ?? 0.0
self.init(x, y, z)
}
}