I am working on SwiftData model that a field for details
. This field can be of various types based on what type
model was created with. Right now I have defined possible types and structs for these, but am unable to figure out how to add such "dynamic" type to details
field, in a way that conforms to SwiftData restrictions as well. Below is simplified implementation (areas marked with ????
are ones I am not sure about):
import SwiftUI
import SwiftData
// Types
enum DetailsType: Codable {
case Time
case Distance
}
struct TimeDetails: Codable {
let startTime: Date
let endTime: Date
}
struct DistanceDetails: Codable {
let distance: Double
}
// Model
@Model class MyModel {
var type: DetailsType
var details: ????
init(type: DetailsType, details: ????) {
self.type = type
self.details = details
}
}
You can't use generics with SwiftData models (or inheritance) so I see two approaches
First one is to add all enum values as properties and make them optional and use the type
property to determine what properties to access.
@Model class MyModel {
var type: DetailsType
var distance: DistanceDetails?
var time: TimeDetails?
private init(type: DetailsType, distance: DistanceDetails? = nil, time: TimeDetails? = nil) {
self.type = type
self.distance = distance
self.time = time
}
convenience init(distance: DistanceDetails) {
self.init(type: .Distance, distance: distance)
}
convenience init(time: TimeDetails) {
self.init(type: .Time, time: time)
}
}
The second one, that I has only tested briefly but that seems to work fine with SwiftData, is to use an enum with associated values.
enum DetailsType: Codable {
case Time(TimeDetails)
case Distance(DistanceDetails)
}
This would clearly simplify the model so to me it looks like the preferred solution if an associated enum is acceptable and SwiftData doesn't throw any surprises on us :)
@Model class MyModelAssociated {
var type: DetailsType
init(type: DetailsType) {
self.type = type
}
}