Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
@propertyWrapper
public struct AnyProxy<EnclosingSelf, Value> {
private let keyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>
public init(_ keyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>) {
self.keyPath = keyPath
}
@available(*, unavailable, message: "The wrapped value must be accessed from the enclosing instance property.")
public var wrappedValue: Value {
get { fatalError() }
set { fatalError() }
}
public static subscript(
_enclosingInstance observed: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Value {
get {
let storageValue = observed[keyPath: storageKeyPath]
let value = observed[keyPath: storageValue.keyPath]
return value
}
set {
let storageValue = observed[keyPath: storageKeyPath]
observed[keyPath: storageValue.keyPath] = newValue
}
}
}
// Kudos @johnsundell for this trick
// https://swiftbysundell.com/articles/accessing-a-swift-property-wrappers-enclosing-instance/
extension NSObject: ProxyContainer {}
public protocol ProxyContainer {
typealias Proxy<T> = AnyProxy<Self, T>
}
@jegnux
Copy link
Author

jegnux commented Feb 27, 2020

Example

😒 😏
BEFORE AFTER

⚠️ Warning

This makes use of a non-documented feature of @propertyWrapper that allows access to EnclosingSelf. Though this feature is already available since Xcode 11, as it powers the "synthesized objectWillChange in @Published SwfitUI/Combine property wrapper", please use it at your own risk.

More info: [SE-0258] Property Wrappers → Future Directions → Referencing the enclosing self in a wrapper type

@plantpurecode
Copy link

plantpurecode commented Feb 27, 2020

💯

@dmhts
Copy link

dmhts commented Feb 28, 2020

🙇‍♂️

@jegnux
Copy link
Author

jegnux commented Jan 20, 2021

@JohnSundell wrote a blog post about this trick and adds a really nice trick to avoid type repetition in the key path:
https://swiftbysundell.com/articles/accessing-a-swift-property-wrappers-enclosing-instance/

@ytyubox
Copy link

ytyubox commented Mar 26, 2021

Please consider a unavailable to wrappedValue, it makes it more friendly since it provides a build Error for accidentally put Proxy in a struct.

@available(*, unavailable, message: "Proxy should be in a class")
 public var wrappedValue: Value {
        get { fatalError() }
        set { fatalError() }
    }

@jegnux
Copy link
Author

jegnux commented Mar 26, 2021

@ytyubox that's a good idea thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment