In my app's Settings view, I'd like to let the user decide their favorite color scheme. But ColorScheme
itself cannot be stored with UserDefaults
, because it's not a basic data type. So I write a enum same as ColorScheme
only for storage purpose. I hope to do something like extension ColorScheme: Int
to make the ColorScheme
itself storable to avoid the redundent enum. Can I do that, or smarter way to go?
enum Appearance: Int {
case system
case light
case dark
var colorScheme: ColorScheme? {
switch self {
case .light: .light
case .dark: .dark
default: nil
}
}
}
@AppStorage("appearance") var appearance: Appearance = .system
Picker("Appearance", selection: $appearance) {
Text("System").tag(Appearance.system)
Divider()
Text("Light").tag(Appearance.light)
Text("Dark").tag(Appearance.dark)
}
RawRepresentable
s with Int
/String
raw values can be stored with @AppStorage
. You can retroactively conform ColorScheme
to RawRepresentable
.
extension ColorScheme: RawRepresentable {
public var rawValue: Int {
switch self {
case .light: 1
case .dark: 2
@unknown default: 0
}
}
public init?(rawValue: Int) {
switch rawValue {
case 1: self = .light
case 2: self = .dark
default: return nil
}
}
}
@AppStorage("appearance") var appearance: ColorScheme?
Picker("Appearance", selection: $appearance) {
Text("System").tag(ColorScheme?.none)
Divider()
Text("Light").tag(ColorScheme?(.light))
Text("Dark").tag(ColorScheme?(.dark))
}
That said, I'd still consider using your own Appearance
enum, because there might be more cases added to the built-in ColorScheme
in the future. If somehow a new color scheme is assigned to the @AppStorage
property, you will get a nil
when you try to retrieve it later.