I was trying out sharing logic between propertyWrappers today when I came across some errors I don't fully understand. Both of the implementations I tried result in the same error about the propertyWrapper object not having a wrappedValue
property, however it is provided by a protocol extension/superclass. If I remove the @propertyWrapper
from the struct/class I am able to access wrappedValue
in both of the examples below.
My first attempt put the shared logic in a protocol extension:
protocol P {
associatedtype Value
var rootValue: Value { get }
}
extension P {
var wrappedValue: Value {
return rootValue
}
}
@propertyWrapper
struct S: P { // Error: Property wrapper type 'S' does not contain a non-static property named 'wrappedValue'
var rootValue = "Value"
}
My second attempt used class inheritance and gets the same error:
class C1<Value> {
var rootValue: Value { fatalError() } // fatalError to make simplified version work
var wrappedValue: Value {
return rootValue
}
}
@propertyWrapper
class C2: C1<String> { // Error: Property wrapper type 'C2' does not contain a non-static property named 'wrappedValue'
override var rootValue: String { "Value"}
}
Real world details
In the examples above I could rename rootValue
to wrappedValue
and it would make everything work, however that creates a different issue for the real problem that started my investigation.
What started this was trying to create multiple propertyWrappers around SwiftUI's Environment
propertyWrapper. The reason I tried the above protocol/class approaches is because renaming the variable requires a custom init.:
@propertyWrapper
struct S { // Error: 'init(wrappedValue:)' parameter type ('Environment<Locale>') must be the same as its 'wrappedValue' property type ('Locale') or an @autoclosure thereof
@Environment(\.locale) var wrappedValue
}
Adding a custom init (init() {}
) resolves the error, but defeats the point of reducing boilerplate.
Is anyone able to explain why these don't work and/or a way to make them work?