The struct below will work for primitive data types such as Int
, String
, Double
, etc., Is there a way to make this work for enums so that I won't have to use rawValues an manual parsing?
@propertyWrapper
struct Storage<T> {
let objectName: String
let defaultValue: T
let defaults: UserDefaults
init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
self.objectName = objectName
self.defaultValue = defaultValue
self.defaults = defaults
}
var wrappedValue: T {
get { return self.defaults.object(forKey: self.objectName) as? T ?? self.defaultValue }
set { self.defaults.set(newValue, forKey: self.objectName) }
}
}
Currently my workaround is to wrap the object in another getter and setter for the enum like this.
enum SomeType: String {
case foo, bar, baz
}
class Defaults {
@Storage("object", default: "")
private var: objectContainer: String
var object: SomeType? {
get {
return SomeType(rawValue: self.objectContainer)
}
set {
self.objectContainer = newValue.rawValue ?? ""
}
}
}
I tried to create a different property wrapper specific for RawRepresentable
types but Swift can't infer the type of T
from that.
@propertyWrapper
struct RawRepresentableStorage<T: RawRepresentable> {
let objectName: String
let defaultValue: T
let defaults: UserDefaults
init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
self.objectName = objectName
self.defaultValue = defaultValue
self.defaults = defaults
}
var wrappedValue: T {
get {
guard let object = self.defaults.object(forKey: self.objectName) as? T else {
return self.defaultValue
}
// Error on this line:
// `Cannot convert value of type 'T' to expected argument type 'T.RawValue'`
return T(rawValue: object) ?? self.defaultValue
}
set {
self.defaults.set(newValue.rawValue, forKey: self.objectName)
}
}
}
It also wouldn't be ideal to create Wrapper types for each storable enum within the codebase even if there are just a handful of them
Is there something I'm missing or is this a current limitation of Swift?
In your wrappedValue
getter, you are casting to the wrong type. You are passing object
to T(rawValue:)
, so its type needs to be T.RawValue
, not T
.
@propertyWrapper
struct RawRepresentableStorage<T: RawRepresentable> {
let objectName: String
let defaultValue: T
let defaults: UserDefaults
init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
self.objectName = objectName
self.defaultValue = defaultValue
self.defaults = defaults
}
var wrappedValue: T {
get {
guard let object = self.defaults.object(forKey: self.objectName) as? T.RawValue else {
return self.defaultValue
}
return T(rawValue: object) ?? self.defaultValue
}
set {
self.defaults.set(newValue.rawValue, forKey: self.objectName)
}
}
}