Swift Codable 的包装器,允许对 Codable 类型进行版本控制

版本化编码主工作流程

Swift Codable 的包装器,允许您对类型进行版本控制,并对从该类型的旧版本迁移进行合理化和推理。这对于经常移动的文档类型特别有用。Codable

⚠️ 危险!这还不稳定!在重要的生产项目中使用它之前,请三思而后行。⚠️

具体来说,处理一个非常具体的用例,其中编码对象中有一个键,并且它是对象中其他键的同级。例如,这个:VersionedCodableversion

{
    "version": 1,
    "author": "Anonymous",
    "poem": "An epicure dining at Crewe\nFound a rather large mouse in his stew\nCried the waiter: Don't shout\nAnd wave it about\nOr the rest will be wanting one too!"
}

...将对此表示:

struct Poem {
    var author: String
    var poem: String
}

您声明符合性,如下所示:VersionedCodable

extension Poem: VersionedCodable {
    static let thisVersion: Int? = 2
    
    typealias PreviousVersion = PoemOldVersion
    init(from old: PoemOldVersion) throws {
        self.author = old.author
        self.poem = poem.joined(separator: "\n")
    }
}

您可以拥有调用堆栈允许的任意数量的先前版本。当您到达最旧的版本并且没有该类型的以前版本可以尝试解码时,您可以通过以下方式使编译器工作并告诉解码器停止并引发错误:

struct PoemOldVersion {
    var author: String
    var poem: [String]
}

extension PoemOldVersion: VersionedCodable {
    static let thisVersion: Int? = 1
    
    typealias PreviousVersion = NothingOlder
    // You don't need to provide an initializer here since you've defined `PreviousVersion` as `NothingOlder.`
}

Encoding and decoding

VersionedCodable provides thin wrappers around Swift’s default and functions.JSONEncoder.encode(_:)JSONDecoder.decode(_:from:)

You decode a versioned type like this:

let decoder = JSONDecoder()
try decoder.decode(versioned: Poem.self, from: data) // where `data` contains your old poem

Encoding happens like this:

let encoder = JSONEncoder()
encoder.encode(versioned: myPoem) // where myPoem is of type `Poem` which conforms to `VersionedCodable`

Testing

It is a very good idea to write unit tests that confidence check that you can continue to decode old versions of your types. provides the types to make this kind of migration easy, but you still need to think carefully about how you map fields between different versions of your types.VersionedCodable

Applications

This is mainly intended for situations where you are encoding and decoding complex types such as documents that live in storage somewhere (on someone’s device’s storage, in a database, etc.) In these cases, the format often changes, and decoding logic can often become unwieldy.

VersionedCodable was originally developed for use in Unspool, a photo tagging app for MacOS which is not ready for the public yet.

Still Missing – Wish List

  • Extend and to be able to deal with things other than JSONEncoderDecoder
  • (?) Potentially allow different keypaths to the version field
  • (?) Potentially allow semantically versioned types. (This could be dangerous, though, as semantic versions have a very specific meaning—it’s hard to see how you’d validate that v2.1 only adds to v2 and doesn’t deprecate anything without some kind of static analysis, which is beyond the scope of .)VersionedCodable

GitHub

点击跳转