Open 05109ee7-7cd9-4cd4-92d0-698e676fc6af opened 4 years ago
@swift-ci create
Aside from the bug, providing the special behavior for RawRepresentable
-conforming types through an overload that's resolved statically can still have unexpected behavior. For example, if you were to use @DefaultUserDefaults
in a generic context, e.g.
struct FeaturePlugin<UserDefaultValue> {
@DefaultUserDefaults
var value: UserDefaultValue
init(key: String, value: UserDefaultValue) {
_value = DefaultUserDefaults(key: key, defaultValue: value)
}
}
then the compiler will never choose the specific RawRepresentable
overload for wrappedValue
. One way to fix this (and a workaround for the bug) is to provide the behavior that you want through your own protocol, for example:
protocol UserDefaultsWritable {
static func getValue(for key: String) -> Self?
static func setValue(_ newValue: Self, for key: String)
}
And your property wrapper can look something like this:
@propertyWrapper
struct DefaultUserDefaults<T: UserDefaultsWritable> {
let key: String
let defaultValue: T
var wrappedValue: T {
get { return T.getValue(for: key) ?? defaultValue }
set { T.setValue(newValue, for: key) }
}
}
Then, you can conditionally provide a default implementation for UserDefaultsWritable
for types that conform to RawRepresentable
(and a different default implementation for types that don't) and get the expected behavior. Note that with this approach, you'll have to explicitly specify conformance to UserDefaultsWritable
for any type that you want to use with DefaultUserDefaults
.
Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 1 | |Component/s | Compiler | |Labels | Bug, PropertyWrappers | |Assignee | None | |Priority | Medium | md5: afdba86880c3e9b8dc9febeb4a572395Issue Description:
If I use a @propertyWrapper struct directly, its constrained extension works. However, when used as property wrapper, getter and setter of `wrappedValue` in the extension are not called, instead the general ones are used.