I have a pretty old project on Swift that still uses NSCalendar.Unit
, and it's pretty convenient because its rawValue
is a UInt
that can be stored in my Core Data database. I want to move to newer Swift APIs, so I have to use Set<Calendar.Component>
, but it seems like Calendar.Component
is just a Swift enum without a rawValue
. I have found that it has a hashValue
, but Apple does not recommend to save it, and also Calendar.Component
does not conform to Encodable
. So is there any way to store Set<Calendar.Component>
in Core Data or am I stuck with old NSCalendar.Unit
?
You can make Calendar.Component
conform to RawRepresentable
and hence have a rawValue
and then store it as the RawValue
. Or you can also make it conform to Codable
and then store it as Data
.
extension Calendar.Component: RawRepresentable {
public var rawValue: Int {
switch self {
case .calendar:
return 0
case .day:
return 1
case .era:
return 2
case .hour:
return 3
case .minute:
return 4
case .month:
return 5
case .nanosecond:
return 6
case .quarter:
return 7
case .second:
return 8
case .timeZone:
return 9
case .weekday:
return 10
case .weekdayOrdinal:
return 11
case .weekOfMonth:
return 12
case .weekOfYear:
return 13
case .year:
return 14
case .yearForWeekOfYear:
return 15
}
}
public init?(rawValue: Int) {
switch rawValue {
case 0:
self = .calendar
case 1:
self = .day
case 2:
self = .era
case 3:
self = .hour
case 4:
self = .minute
case 5:
self = .month
case 6:
self = .nanosecond
case 7:
self = .quarter
case 8:
self = .second
case 9:
self = .timeZone
case 10:
self = .weekday
case 11:
self = .weekdayOrdinal
case 12:
self = .weekOfMonth
case 13:
self = .weekOfYear
case 14:
self = .year
case 15:
self = .yearForWeekOfYear
default:
return nil
}
}
}
Codable
conformance isn't necessary, RawRepresentable
should be enough, but leaving it here as a reference.
extension Calendar.Component: Codable {
enum DecodingError: Error {
case unknownRawValue
}
/// Throwable initialiser that throws when an unknown `RawValue` is passed to it
/// Necessary for `init(from decoder:)` to be able to delegate to a non-failable init
init(value: Int) throws {
guard let component = Calendar.Component(rawValue: value) else {
throw DecodingError.unknownRawValue
}
self = component
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let rawValue = try container.decode(Int.self)
try self.init(value: rawValue)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self.rawValue)
}
}