我很好奇,是否有一些最佳实践被公认为是在Swift中跨模式更改迁移可编码数据的好方法?
例如,我可能:
struct RecordV1: Codable {
var name: String
}
struct RecordV2: Codable {
var firstName: String // Renamed old name field
var lastName: String // Added this field
}
我希望能够将保存为RecordV 1的内容加载到RecordV 2中。
我希望以这样一种方式实现我的数据结构,即所存储的内容具有嵌入其中的版本号,以便在将来,当加载数据时,当较新版本的代码与较新版本的数据一起工作时,某些机制将有机会将旧数据迁移到最近的模式中。我希望解决方案是相当优雅的,不涉及大量的重新输入样板代码。越快越好!
1条答案
按热度按时间kmpatx3s1#
我已经搜索了很多地方,但是我还没有找到任何关于这个问题的解决方案。下面是我能想到的最好的解决方案。如果人们能提出替代方案(特别是使用合并,或者以更好的方式使用协议和泛型),我会很高兴。
原谅这篇文章的长度。我会把它分解成几个部分,但是把它们都粘贴到一个Swift Playground中,它应该会工作。
第一部分是定义可迁移结构的协议,定义标识MigratableData版本的方法,定义从以前版本保存的结构导入数据的初始化器,还有一个
init(from: withVersion: using:)
,它爬上迁移链,解码正确版本的数据,然后将结构向前迁移到当前版本。我实现了
init(from: withVersion: using:)
方法作为默认协议实现。我特别关注this article,它暗示这是一个坏主意。我很想知道如何避免这个问题。一旦我们有了这个协议,就只需要定义一些结构并在它们之间建立连接--隐式地使用版本号和
init(from:)
:为了使用它,并证明它是有效的,我们可以做以下几点:
所以撇开所有缺点不谈,上面的工作方式是我想要的。我只是不喜欢在加载时跟踪要迁移的版本(
withVersion:
参数)。理想情况下,版本号应该是保存的数据的一部分,这样它就可以被自动读取和应用。到目前为止,我最好的解决方案是将数据结构 Package 在一个名为MDWrapper的泛型中:
我不得不做各种各样的跳跃通过箍工作。同样,建设性的批评将是最受欢迎的。这里有一些更多的测试来证明这一工作,正如你可以看到手册版本号已经消失: