通用可编码类型

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"
      }
    }
  ]
}

本质上,数组中的每一项现在都是一个具有单个键的对象。来自 checkListCellsegmentedCell。这将来自您枚举的任何案例。此键告诉您的应用程序对象是哪种类型的单元格。

那么针对该键显示的对象就是底层单元格本身。

这可能是对这些数据建模的最简洁的方法。

因此,您可能有两个清单单元格,然后是一个分段单元格,最后是另一个清单单元格。

这看起来像...

{
  "cells": 
  [
    {
      "checkListCell": { 
        "header": "First checklist"
      }
    },
    {
      "checkListCell": { 
        "header": "Second checklist"
      }
    },
    {
      "segmentedCell": {
        "title": "Some segmented stuff"
      }
    },
    {
      "checkListCell": { 
        "header": "Another checklist"
      }
    },
  ]
}

在分析这个 JSON 时要考虑的重要事情不是你(作为一个人)更难阅读。但这对于您的应用程序来说是必需的,而且实际上相当容易阅读 decode/encode.

希望这是有道理的。