I have a simple property wrapper written to easily get and set user preferences in the UserDefaults.
@propertyWrapper
struct UserDefault<Value> {
let key: String
let defaultValue: Value
var wrappedValue: Value {
get { UserDefaults.standard.object(forKey: key) as? Value ?? defaultValue }
set { UserDefaults.standard.set(newValue, forKey: key) }
}
}
// Example usage
@UserDefault(key: "com.example.flag", defaultValue: false)
var trackingEnabled: Bool
Now this works fine for static preferences, but say I were to support multiple users and each of them would be able to store their settings.
struct Person {
let id: UUID
let name: String
@UserDefault(key: "com.example.person.\(id)", defaultValue: false)
var trackingEnabled: Bool
}
This gives me the warning Cannot use instance member 'id' within property initializer; property initializers run before 'self' is available
. Is there a way to solve this so I can easily use this property wrapper with a dynamic key?
In order to use the value of id
in the initialization of trackingEnabled
, you can use a custom initializer for your struct:
struct Person {
let id: UUID
let name: String
var trackingEnabled: UserDefault<Bool>
init(id: UUID, name: String) {
self.id = id
self.name = name
trackingEnabled = UserDefault(key: "com.example.person.\(id)", defaultValue: false)
}
}
Or, you can define trackingEnabled
as lazy
, so that it has access to the id
parameter by the time it's initialized:
struct Person {
let id: UUID
let name: String
lazy var trackingEnabled = UserDefault(key: "com.example.person.\(id)", defaultValue: false)
}
Neither solution uses the @propertyWrapper
aspect of UserDefault
, but it doesn't seem necessary here -- it still results in the same type/functionality.