通用可编码类型
Generic Codable types
我有一个想法,我正在尝试测试,我希望能够拥有一组不同的对象,这些对象都是 Codable。
这是json
{
"cells":
[
{
"header": "dummy header"
},
{
"title": "dummy title"
}
]
}
还有一张来自 Firestore 的图片,因为我不确定我写的 json 是否正确:
这是我目前使用泛型测试的结果
struct Submission<Cell: Codable>: Codable {
let cells: [Cell]
}
struct ChecklistCell: Codable {
let header: String
}
struct SegmentedCell: Codable {
let title: String
}
总体目标是解码具有(单元格)数组的文档,这些数组可以是不同类型,但都是可编码的。我不确定这是否可行,或者是否有更好的方法。谢谢
更新:
我做了@Fogmeister 的解决方案并让它工作,但不是最理想的结果。它为 json 添加了一个理想情况下不会存在的怪异层。有什么想法吗?
我以前做过类似的事情。不是使用 Firestore(尽管最近我使用了),而是使用了我们使用的 CMS。
正如@vadian 指出的那样,Swift 不支持异构数组。
另外...还有一点要指出。
当您将通用类型定义为...
struct Submission<Cell> {
let cells: [Cell]
}
那么,根据定义,cells
是单一类型的齐次数组。如果您尝试将不同的类型放入其中,它将无法编译。
您可以通过使用枚举将所有不同的 Cell 捆绑成一个类型来解决这个问题。
enum CellTypes {
case checkList(CheckListCell)
case segmented(SegmentedCell)
}
现在你的数组将是一个 [CellTypes]
的同构数组,其中每个元素都是枚举的一个例子,然后包含其中的单元格模型。
struct Submission {
let cells: [CellTypes]
}
这需要一些自定义解码才能直接从 JSON 获得,但我现在无法添加。如果您需要一些指导,我会更新答案。
编码和解码
从 JSON 的角度来看需要注意的事项。您的应用需要知道正在使用哪种类型的单元 encoded/decoded。因此,您的原始 JSON 架构需要进行一些更新才能添加此内容。
您展示的来自 Firestore 的自动更新是一种相当常见的执行此操作的方式...
JSON有点像这样...
{
"cells":
[
{
"checkListCell": {
"header": "dummy header"
}
},
{
"segmentedCell": {
"title": "dummy title"
}
}
]
}
本质上,数组中的每一项现在都是一个具有单个键的对象。来自 checkListCell
、segmentedCell
。这将来自您枚举的任何案例。此键告诉您的应用程序对象是哪种类型的单元格。
那么针对该键显示的对象就是底层单元格本身。
这可能是对这些数据建模的最简洁的方法。
因此,您可能有两个清单单元格,然后是一个分段单元格,最后是另一个清单单元格。
这看起来像...
{
"cells":
[
{
"checkListCell": {
"header": "First checklist"
}
},
{
"checkListCell": {
"header": "Second checklist"
}
},
{
"segmentedCell": {
"title": "Some segmented stuff"
}
},
{
"checkListCell": {
"header": "Another checklist"
}
},
]
}
在分析这个 JSON 时要考虑的重要事情不是你(作为一个人)更难阅读。但这对于您的应用程序来说是必需的,而且实际上相当容易阅读 decode/encode.
希望这是有道理的。
我有一个想法,我正在尝试测试,我希望能够拥有一组不同的对象,这些对象都是 Codable。
这是json
{
"cells":
[
{
"header": "dummy header"
},
{
"title": "dummy title"
}
]
}
还有一张来自 Firestore 的图片,因为我不确定我写的 json 是否正确:
这是我目前使用泛型测试的结果
struct Submission<Cell: Codable>: Codable {
let cells: [Cell]
}
struct ChecklistCell: Codable {
let header: String
}
struct SegmentedCell: Codable {
let title: String
}
总体目标是解码具有(单元格)数组的文档,这些数组可以是不同类型,但都是可编码的。我不确定这是否可行,或者是否有更好的方法。谢谢
更新:
我以前做过类似的事情。不是使用 Firestore(尽管最近我使用了),而是使用了我们使用的 CMS。
正如@vadian 指出的那样,Swift 不支持异构数组。
另外...还有一点要指出。
当您将通用类型定义为...
struct Submission<Cell> {
let cells: [Cell]
}
那么,根据定义,cells
是单一类型的齐次数组。如果您尝试将不同的类型放入其中,它将无法编译。
您可以通过使用枚举将所有不同的 Cell 捆绑成一个类型来解决这个问题。
enum CellTypes {
case checkList(CheckListCell)
case segmented(SegmentedCell)
}
现在你的数组将是一个 [CellTypes]
的同构数组,其中每个元素都是枚举的一个例子,然后包含其中的单元格模型。
struct Submission {
let cells: [CellTypes]
}
这需要一些自定义解码才能直接从 JSON 获得,但我现在无法添加。如果您需要一些指导,我会更新答案。
编码和解码
从 JSON 的角度来看需要注意的事项。您的应用需要知道正在使用哪种类型的单元 encoded/decoded。因此,您的原始 JSON 架构需要进行一些更新才能添加此内容。
您展示的来自 Firestore 的自动更新是一种相当常见的执行此操作的方式...
JSON有点像这样...
{
"cells":
[
{
"checkListCell": {
"header": "dummy header"
}
},
{
"segmentedCell": {
"title": "dummy title"
}
}
]
}
本质上,数组中的每一项现在都是一个具有单个键的对象。来自 checkListCell
、segmentedCell
。这将来自您枚举的任何案例。此键告诉您的应用程序对象是哪种类型的单元格。
那么针对该键显示的对象就是底层单元格本身。
这可能是对这些数据建模的最简洁的方法。
因此,您可能有两个清单单元格,然后是一个分段单元格,最后是另一个清单单元格。
这看起来像...
{
"cells":
[
{
"checkListCell": {
"header": "First checklist"
}
},
{
"checkListCell": {
"header": "Second checklist"
}
},
{
"segmentedCell": {
"title": "Some segmented stuff"
}
},
{
"checkListCell": {
"header": "Another checklist"
}
},
]
}
在分析这个 JSON 时要考虑的重要事情不是你(作为一个人)更难阅读。但这对于您的应用程序来说是必需的,而且实际上相当容易阅读 decode/encode.
希望这是有道理的。