giik
(Giik)
1
I need to conform a custom type T to Codable and one of the stored properties of T is a heterogeneous array like so:
// There are currently 5-6 conforming types and this number is expected
// to change slowly.
protocol FooProtocol { ... }
struct T {
var foos: [FooProtocol]
...
}
Is there a commonly accepted way / idiom(s) for dealing with this situation? I've considered the following:
- inheriting
FooProtocol from Codable, this will require all types conforming to FooProtocol to also implement Codable conformance,
- in this particular case,
FooProtocol and its conforming types can be replaced with an enum with associated values, which depending on the associated values can be automatically conforming to Codable,
- anything else?
In my particular case, I think 2. above is the best solution but this may not always be possible. In that case I am left with 1. or are there any alternatives that I should know of?
Cheers,
tera
2
I'd go with an enum, in this case it'll work out of the box.
Could you give an example?
bbrk24
3
I don't think #1 is sufficient. Say two types implementing the protocol have properties with the same names, but use those properties for different things, or expose different methods. From the serialized properties alone it isn't possible to tell which type it originally was, even with the restriction of some FooProtocol & Codable.
1 Like
Dlemex
(David Edwards)
4
I had a situation like this recently. I was able to accomplish this cleanly with an enum and then I had codable structures with arrays of these entities. Also, by making all the records (which are codable structs) use a protocol for the common fields, I am able to access those values directly from the enum.
public enum CSSEntity: Equatable, Codable, Sendable {
case dataset(DatasetRecord)
case datasetSupplement(SupplementRecord)
case master(MasterRecord)
case masterSupplement(SupplementRecord)
case primary(PrimaryRecord)
case report(ReportRecord)
case asset(AssetRecord)
public var entityType: CSSEntityType {
switch self {
case .dataset: return .dataset
case .datasetSupplement: return .datasetSupplement
case .master: return .master
case .masterSupplement: return .masterSupplement
case .primary: return .primary
case .report: return .report
case .asset: return .asset
}
}
/// Return the record with common fields identified
var value: AnyDBObject {
switch self {
case .dataset(let datasetRecord):
return datasetRecord
case .datasetSupplement(let supplementRecord):
return supplementRecord
case .master(let masterRecord):
return masterRecord
case .masterSupplement(let supplementRecord):
return supplementRecord
case .primary(let primaryRecord):
return primaryRecord
case .report(let reportRecord):
return reportRecord
case .asset(let assetRecord):
return assetRecord
}
}
}