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.
As @vadian pointed out, heterogeneous arrays are not supported by Swift.
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. 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.
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.
struct Submission {
let cells: [CellTypes]
}
This takes some custom decoding to get straight from JSON but I can't add that right now. If you need some guidance on that I'll update the answer.
Encoding and Decoding
Something to note from a JSON point of view. 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.
The automatic update from Firestore that you have shown is a fairly common way of doing this...
The JSON looks a bit like this...
{
"cells":
[
{
"checkListCell": {
"header": "dummy header"
}
},
{
"segmentedCell": {
"title": "dummy title"
}
}
]
}
Essentially, each item in the array is now an object that has a single key. From checkListCell, segmentedCell. This will be from any of the cases of your enum. This key tells your app which type of cell the object is.
Then the object shown against that key is then the underlying cell itself.
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. But that it's required, and actually fairly easy, for your app to read and decode/encode.
Hope that makes sense.
Codablecompliant data structures. Heterogenous arrays are not supported in Swift by default. With your code you cannot decodeChecklistCellandSegmentedCellsimultaneously. The synthesized implementation supports only homogenous arrays.