解码Swift类型,它是带有额外Codable属性的包装Codable类型

时间:2019-04-10 15:20:51

标签: swift codable

我有一个Codable类型,例如Car,其定义为:

struct Car: Codable {
    let age: Int
    let color: String
}

我可以对它进行编码/解码。

在我的持久性系统中,存储对象时会为其分配一个_id属性,该属性是一个String,例如5cae04b533376609456d40ed

这样,当我从持久性存储中读取Data并尝试对其进行解码时,其中存在表示_id属性及其关联的String值的额外字节。

我无法控制可以编码和存储在商店中的各种类型。对其的唯一限制是它们是Codable

我想做的是将从商店读取时得到的Data(包括_id东西)解码为类似Wrapped<T: Codable>的类型,它将被定义为以下形式(最简单的形式):

struct Wrapped<T: Codable> {
    let _id: String
    let value: T
}

但是,我不确定要解决这个问题。

我做过的尝试是定义一个自定义decode函数,但是由于我似乎无法访问T类型的CodingKeys,这并没有太大的意义,这使得据我所知,用这种方法不可能做到。

也许还有另一种方法可以使事情如我所愿?

2 个答案:

答案 0 :(得分:1)

您可以为您的Wrapped类型编写一个自定义解码函数,该函数解析出_id,然后将解码器传递给包装的类型,以便它可以解码自己的属性:

struct Wrapped<T: Codable>: Decodable {
    let _id: String
    let value: T

    private enum CodingKeys: String, CodingKey {
        case _id
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        _id = try container.decode(String.self, forKey: ._id)
        value = try T(from: decoder)
    }
}

答案 1 :(得分:0)

您可以通过定义自定义_id并从此处省略CodingKeys来简单地声明不应解码_id属性。如果要使用自动合成的初始化程序,还需要为未解码的属性(在您的情况下为_id)分配一个默认值。

对于具体类型:

struct Car: Codable {
    let age: Int
    let color: String
    let _id:Int = 0

    enum CodingKeys: String, CodingKey {
        case age, color
    }
}

您可以为所有持久化类型实现此目标。

如果您不想为所有持久化类型创建CodingKeys枚举,则可以遵循开始时使用的通用包装类型方法,但是您需要创建自定义的init(from:)和{{ 1}}方法。

encode(to:)