简体   繁体   English

通用可编码类型

[英]Generic Codable types

I've got an idea that I'm trying to test out, I want to be able to have an array of different objects that are all Codable.我有一个想法,我正在尝试测试,我希望能够拥有一系列不同的对象,这些对象都是 Codable 的。

Here is the json这是json

{
  "cells": 
  [
    { 
      "header": "dummy header"
    },
    {
      "title": "dummy title"
    }
  ]
}

Also a picture from Firestore because I'm not sure if I wrote that json out correctly:还有一张来自 Firestore 的图片,因为我不确定我是否正确地写出了 json: Firestore 模式

Here's what I had so far testing with generics这是我到目前为止用 generics 测试的内容

struct Submission<Cell: Codable>: Codable {
    let cells: [Cell]
}

struct ChecklistCell: Codable {
    let header: String
}

struct SegmentedCell: Codable {
    let title: String
}

The overarching goal is to decode a document that has an array (of cells) that can be different types, but are all codable.总体目标是解码具有数组(单元格)的文档,这些数组可以是不同类型,但都是可编码的。 I'm not sure if this is possible, or if there is an even better approach.我不确定这是否可行,或者是否有更好的方法。 Thanks.谢谢。

Update:更新: 更新 I did @Fogmeister 's solution and got it working, but not the most desirable outcome.我做了@Fogmeister 的解决方案并让它工作,但不是最理想的结果。 It adds a weird layer to the json that ideally wouldn't be there.它为 json 添加了一个奇怪的层,理想情况下它不会存在。 Any ideas?有任何想法吗?

I have done something similar to this in the past.我过去做过类似的事情。 Not with Firestore (although, more recently I did) but with our CMS that we use.不是使用 Firestore(尽管最近我使用了),而是使用了我们使用的 CMS。

As @vadian pointed out, heterogeneous arrays are not supported by Swift.正如@vadian 指出的那样,Swift 不支持异构 arrays。

Also... something else to point out.还有……还有一点要指出。

When you have a generic type defined like...当你定义了一个泛型类型时......

struct Submission<Cell> {
  let cells: [Cell]
}

Then, by definition, cells is a homogeneous array of a single type.那么,根据定义, cells就是单一类型的同构数组。 If you try to put different types into it it will not compile.如果您尝试将不同的类型放入其中,它将无法编译。

You can get around this though by using an enum to bundle all your different Cells into a single type.不过,您可以通过使用枚举将所有不同的 Cell 捆绑成一个类型来解决这个问题。

enum CellTypes {
  case checkList(CheckListCell)
  case segmented(SegmentedCell)
}

Now your array would be a homogeneous array of [CellTypes] where each element would be a case of the enum which would then contain the model of the cell inside it.现在您的数组将是[CellTypes]的同构数组,其中每个元素都是枚举的一个例子,然后包含其中单元格的 model。

struct Submission {
  let cells: [CellTypes]
}

This takes some custom decoding to get straight from JSON but I can't add that right now.这需要一些自定义解码才能直接从 JSON 获得,但我现在无法添加它。 If you need some guidance on that I'll update the answer.如果您需要一些指导,我会更新答案。

Encoding and Decoding编解码

Something to note from a JSON point of view.从 JSON 的角度来看需要注意的事项。 Your app will need to know which type of cell is being encoded/decoded.您的应用程序需要知道正在编码/解码的是哪种类型的单元格。 So your original JSON schema will need some updating to add this.所以你原来的 JSON 模式需要一些更新来添加它。

The automatic update from Firestore that you have shown is a fairly common way of doing this...您展示的来自 Firestore 的自动更新是一种相当常见的执行此操作的方式......

The JSON looks a bit like this... JSON 看起来有点像这样......

{
  "cells": 
  [
    {
      "checkListCell": { 
        "header": "dummy header"
      }
    },
    {
      "segmentedCell": {
        "title": "dummy title"
      }
    }
  ]
}

Essentially, each item in the array is now an object that has a single key.本质上,数组中的每一项现在都是一个具有单个键的 object。 From checkListCell , segmentedCell .来自checkListCellsegmentedCell This will be from any of the cases of your enum.这将来自您枚举的任何案例。 This key tells your app which type of cell the object is.此密钥告诉您的应用程序 object 是哪种类型的单元格。

Then the object shown against that key is then the underlying cell itself.然后针对该键显示的 object 就是底层单元格本身。

This is probably the cleanest way of modelling this data.这可能是对这些数据建模的最简洁的方法。

So, you might have two checklist cells and then a segmented cell and finally another checklist cell.因此,您可能有两个清单单元格,然后是一个分段单元格,最后是另一个清单单元格。

This will look like...这看起来像...

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

The important thing to think when analysing this JSON is not that it's harder for you (as a human being) to read.在分析这个 JSON 时要考虑的重要事情不是你(作为一个人)更难阅读。 But that it's required, and actually fairly easy, for your app to read and decode/encode.但它是必需的,而且实际上相当容易,因为您的应用程序可以读取和解码/编码。

Hope that makes sense.希望这是有道理的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM