为ARAnchor实现Codable:“无法在扩展中自动合成...”

3

代码extension ARAnchor:Codable {}会产生错误:

"在不同文件中的扩展中无法自动合成'Decodable'的实现".

这是什么意思?我能够以类似的方式为另一个本地类型实现Codable而没有任何错误。

最初的回答:

这个错误发生时,编译器无法自动为您的扩展合成给定的协议。这可能是因为该扩展定义在不同的文件中或由于其他原因导致了此问题。 您可以尝试将其放入相同的文件中,或者根据需要手动实现所需的协议方法以解决此问题。


你的成功扩展是在同一个文件中吗? - undefined
不,这是为了另一个本地类型在它自己的文件中。 - undefined
3个回答

8
您可以创建一个实现了Codable的容器对象,然后使用它来对锚点进行编码和解码。我在playground中尝试了这个代码,并且它对我有效。您需要根据您想要从锚点获取哪些数据来进行调整;例如,我编码了name,但如果您的锚点没有初始化名称,则这可能是无用的,甚至会导致错误。您也可以使用simd_float4x4来做同样的事情。
import Foundation
import ARKit

class AnchorContainer: Codable {
    
    let anchor: ARAnchor
    
    init(anchor: ARAnchor) {
        self.anchor = anchor
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let name = try container.decode(String.self, forKey: .name)
        let transform0 = try container.decode(simd_float4.self, forKey: .transform0)
        let transform1 = try container.decode(simd_float4.self, forKey: .transform1)
        let transform2 = try container.decode(simd_float4.self, forKey: .transform2)
        let transform3 = try container.decode(simd_float4.self, forKey: .transform3)
        let matrix = simd_float4x4(columns: (transform0, transform1, transform2, transform3))
        anchor = ARAnchor(name: name, transform: matrix)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(anchor.name, forKey: .name) // Might want to make sure that the name is not nil here
        try container.encode(anchor.transform.columns.0, forKey: .transform0)
        try container.encode(anchor.transform.columns.1, forKey: .transform1)
        try container.encode(anchor.transform.columns.2, forKey: .transform2)
        try container.encode(anchor.transform.columns.3, forKey: .transform3)
    }
    
    enum CodingKeys: String, CodingKey {
        case name
        case transform0
        case transform1
        case transform2
        case transform3
    }
    
}

// EXAMPLE:

let anchor = ARAnchor(name: "Bill", transform: simd_float4x4(float4(repeating: 4), float4(repeating: 5), float4(repeating: 6), float4(repeating: 7))) // Make a arbitrary anchor
print(anchor) // Figure out what it's value is


do {
    let data = try JSONEncoder().encode(AnchorContainer(anchor: anchor))
    let anchorDecode = try JSONDecoder().decode(AnchorContainer.self, from: data)
    print(anchorDecode.anchor) // Print the value after decoding to make sure that the result is the same
} catch {
    print(error.localizedDescription)
}

分解矩阵非常有意义。我正在探索这个选项,因为 simd_float4x4 类型可能导致编码问题。太棒了! - undefined

5
目前据我所知,Swift编译器不支持在不同的源文件中综合符合CodableEquatableHashable。有关此问题的跟踪,请参见https://bugs.swift.org/browse/SR-6101。请注意保留HTML标记。

哇,肯定有个变通方法吧?如何将Codable添加到不支持它的原生类型中呢? - undefined
我相信你现在不能,至少不能让编译器合成它。不过,实现init(coder:)decode(from:)仍然是一个选择。 - undefined

0

由于CodableEncodableDecodable协议的类型别名,当您将其用作类型泛型约束时,它匹配任何符合这两个协议的类型:

public typealias Codable = Decodable & Encodable

目前(Xcode 10.2.1 / Swift 5.0.1),如果一个文件中的扩展添加了不同文件中的一致性,Codable 尚未得到支持。请查看 https://bugs.swift.org/。希望这可以帮助您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接