使用任何类型的 Codable 对象创建 Codable 对象?

Creating Codable object with Codable objects of any type?

我想创建一个 class 来存储 Date 和任何符合 Codable 协议的对象。我希望这个 class 也符合 Codable 协议本身。

我可以按如下方式为一个对象执行此操作:

class CodableContainerA: NSObject, Codable {
    var date: Date?
    var item: CodableTypeA?
}

我宁愿不必为我拥有的每个 CodableTypeX 创建一个单独的 CodableContainerX。

我目前的解决方法是创建一个名为 CodableBaseClass 的 class,它符合 Codable,从中派生每个 CodableType 并按如下方式定义我的 class:

class CodableContainer: NSObject, Codable {
    var date: Date?
    var item: CodableBaseClass?
}

这似乎还有很长的路要走,感觉我应该能够通过使 CodableType 符合协议来做到这一点,但我不确定如何做。如果我将 item 定义为 Codable?(Any & Codable)? 类型,我会收到一条错误消息

Type 'CodableContainer' does not conform to protocol 'Decodable'

我正在使用 Swift 4.

我们将不胜感激地接受任何帮助或建议。非常感谢,

这就是通用 类 的用途:

class CodableContainer<T: Codable>: NSObject, Codable {
    var date: Date?
    var item: T?
}

每当您发现自己对每个基础类型的单独 class 感到疑惑时,请考虑 "generics"。例如。

struct CodableContainer<T: Codable>: Codable { 
    let date: Date
    let item: T
}
  • 除非您出于某些特定原因需要 class,否则我会使用 struct
  • 我会让属性不可变,除非您出于某种原因需要它们可变。
  • 我不会 subclass NSObject 除非有一些特定的原因需要这个特定的容器 NSObject subclass.
  • 除非您绝对需要它们是可选的,否则我会将这些属性设置为非可选的。

但请按您认为合适的方式进行编辑。关键点是 generic 模式。


您可能需要一个使用一些一致的 DateDecodingStrategy 进行解码的解码函数,例如

extension CodableContainer {
    static func decodeJSON(_ data: Data) throws -> CodableContainer {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        return try decoder.decode(self, from: data)
    }
}

显然,使用任何你想要的 dateDecodingStrategy。但是你可以解码:

let result = try CodableContainer<Foo>.decodeJSON(data)