Some property wrappers store their wrappedValue
s inside some external storage (like UserDefaults, View Environment etc.) rather than storing it in-place. So if for convenience' sake we separate property wrappers into two types where first type would be like this:
@propertyWrapper
struct FirstWrapper {
var wrappedValue: Int
}
and second type would be like this:
@propertyWrapper
struct SecondWrapper {
var wrappedValue: Int {
get {
defaults.integer(forKey: key)
}
nonmutating set {
defaults.set(newValue, forKey: key)
}
}
let defaults: UserDefaults
let key: String
}
// or
@propertyWrapper
struct SecondWrapper {
var wrappedValue: Int {
fatalError("Unimplemented")
}
let defaults: UserDefaults
let key: String
static subscript<T>(
_enclosingInstance instance: T,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<T, Int>,
storage storageKeyPath: ReferenceWritableKeyPath<T, Self>
) -> Int {
get {
let wrapper = instance[keyPath: storageKeyPath]
return wrapper.defaults.integer(forKey: wrapper.key)
}
set {
let wrapper = instance[keyPath: storageKeyPath]
wrapper.defaults.set(newValue, forKey: wrapper.key)
}
}
}
I propose to allow declaring propertyWrapper
s of second type in extensions like so:
extension Foo {
@SecondWrapper(defaults: .standard, key: "bar")
var bar: Int
}
which would be then desugarized to
extension Foo {
var _bar: SecondWrapper {
SecondWrapper(defaults: .standard, key: "bar")
}
var bar: Int {
get {
_bar.wrappedValue
}
set {
_bar.wrappedValue = newValue
}
}
// or
var bar: Int {
get {
_bar[self, wrapped: \.bar, storage: \._bar]
}
set {
_bar[self, wrapped: \.bar, storage: \._bar] = newValue
}
}
}