So I have a protocol with roughly this structure:
protocol Content: Codable {
var type: ContentType { get }
associatedtype ContentData: Codable
var data: ContentData { get set }
var id: UUID { get }
...
}
and I have an enum like this:
enum ContentType: String, Equatable, CaseIterable, Codable, RawRespresentable {
case type1 = "Type 1"
case type2 = "Type 2"
}
And then I have an object using Swift's new 5.7 syntax that holds the mixed types of Content
like this:
class ContentCollection: Codable {
var contents: [any Content]
...
}
So I'm able to decipher which type of content it is from the type property on any piece of any Content
and properly type cast it like this:
for content in contents {
switch content.type {
case .type1:
let typedContent = content as! Type1
try container.encode(typedContent, forKey: .contents)
case .type2:
let typedContent = content as! Type2
try container.encode(typedContent, forKey: .contents)
...
}
}
But that just writes the single piece of content over the whole array. How do you encode a single piece at a time and add it to the JSON array? I'm fairly new to Codable so forgive me if I"m missing something obvious.
And similarly, how would you decode it back?
Thanks!
@Sweeper answered it.
For decoding I did this:
var contentsContainer = try container.nestedUnkeyedContainer(forKey: .contents)
var contents: [any Content] = []
while !contentsContainer.isAtEnd {
// try to decode as every type of Content
contents.append(try contentsContainer.decode(ContentType1.self))
contents.append(try contentsContainer.decode(ContentType2.self))
contents.append(try contentsContainer.decode(ContentType3.self))
}
self.contents = contents
and encoding I did this:
var contentsContainer = container.nestedUnkeyedContainer(forKey: .contents)
for content in contents {
switch content.type {
case .contentType1:
try contentsContainer.encode(content as! ContentType1)
case .contentType2:
try contentsContainer.encode(content as! ContentType2)
case .contentType3:
try contentsContainer.encode(content as! ContentType3)
}
}