I am trying to come up with a way to access UserDefaults using properties. However, I am stuck because I can't figure out how to make the properties dynamic, so to speak.
This is the generic idea, that API that I want:
class AppUserDefaults {
var username = DefaultsKey<String>("username", defaultValue: "Unknown")
var age = DefaultsKey<Int?>("age", defaultValue: nil)
}
let props = AppUserDefaults()
props.username = "bla"
print("username: \(props.username)")
But that (of course) doesn't work, since the type is DefaultsKey<String>, not String. So I have to add a value property to the DefaultsKey implementation just to add the getter and the setter, like this:
struct DefaultsKey<ValueType> {
private let key: String
private let defaultValue: ValueType
public init(_ key: String, defaultValue: ValueType) {
self.key = key
self.defaultValue = defaultValue
}
var value: ValueType {
get {
let value = UserDefaults.standard.object(forKey: key)
return value as? ValueType ?? defaultValue
}
set {
UserDefaults.standard.setValue(newValue, forKey: key)
UserDefaults.standard.synchronize()
}
}
}
and then use it like this:
let props = AppUserDefaults()
props.username.value = "bla"
print("username: \(props.username.value)")
But I find that rather ugly. I also tried a subscript method, but then you're still required to add [] instead of .value:
struct DefaultsKey<ValueType> {
...
subscript() -> ValueType {
get {
let value = UserDefaults.standard.object(forKey: key)
return value as? ValueType ?? defaultValue
}
set {
UserDefaults.standard.setValue(newValue, forKey: key)
UserDefaults.standard.synchronize()
}
}
}
let props = AppUserDefaults()
props.username[] = "bla"
print("username: \(props.username[])")
Basically what I want is that I can define the getter and the setter directly on DefaultsKey instead of having to go through that value property. Is this simply not possible with Swift? Is there another way to get the behaviour that I want, where properties defined on AppUserDefaults are "dynamic" and go through a getter and setter, without having to define it on the property declaration inside of AppUserDefaults?
I hope I am using the correct terms here and made the question clear for everyone.