Storing an Enum in CoreData
One of the things that I have taken a liking to in Swift is Enumerations (or enums for short.). From the documentation an “enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.” It allows you to easily a dataset that can be reused throughout your code and since they are first-class types, they adopt many features traditionally supported by classes, such as computed properties.
Using a enum in SwiftData is as easy as defining the enum and using it in the model. Using it in CoreData is a little bit more complicated. CoreData does not directly support enum as a data type for attributes, but if you create the enum with a raw value type that CoreData can handle you can then create a computed property that will store and retrieve the raw value from CoreData.
For my application, I had an enumeration for the days of the week so that you could choose which days you want to do a routine. I started by creating an enum that included the days of the week, and a few computed variables.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enum Weekday: Int16, Identifiable, CaseIterable, Codable {
case sunday = 1
case monday = 2
case tuesday = 3
case wednesday = 4
case thursday = 5
case friday = 6
case saturday = 7
var id: Self { self }
/// The capitalized name of the day of the week.
public var name: String {
"\(self)".capitalized
}
/// The first letter of the day of the week.
public var abbreviation: String {
"\(name.first ?? Character(""))"
}
}
If you are just tracking a single value, all you need to do is and an attribute to your CoreData entity and create an extension for the entity and add a computed property to the entity.
1
2
3
4
5
6
7
8
9
10
extension Routine {
var dayScheduled: Weekday {
get {
return Routine(rawValue: self.weekday)
}
set {
self.weekday = Int16(newValue.rawValue)
}
}
}
For my application, you could have as few as one and as many as all the days, so I needed to do things a little differently. I started by creating an entity called WeekdayItem with a single attribute called value
. Then I created a relationshsip between WeekDay and Routine. With Weekday.routine set to one
and Routine.weekdays set to many
. Then, in my Routine extension I created the computed variable WeekdayArray
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var weekdayArray: [Weekday] {
get {
let weekdayItems = weekdays?.allObjects as? [WeekdayItem] ?? []
let sortedItems = weekdayItems.sorted { $0.value < $1.value }
return sortedItems.compactMap { Weekday(rawValue: $0.value) }
}
set {
let context = self.managedObjectContext!
let newWeekdayItems = newValue.map { day in
let item = WeekdayItem(context: context)
item.value = Int16(day.rawValue)
item.list = self
return item
}
weekdays = NSSet(array: newWeekdayItems)
}
}
I do a little extra in my getter, sorting the days as well as just getting them, that way they always come out in order. The setter is a little more complicated as well since now it has to set multiple values in the WeekdayItem