young
(rtSwift)
1
import SwiftUI
@propertyWrapper
struct Wrap {
var wrappedValue: Int
}
extension Wrap: RawRepresentable {
var rawValue: String {
wrappedValue.description
}
init?(rawValue: String) {
guard let value = Int(rawValue) else {
return nil
}
wrappedValue = value
}
}
struct Test {
@AppStorage("x") @Wrap var x: Int = 5
}
var test = Test()
test.x = 6
print(UserDefaults.standard.object(forKey: "x")) // wonderful: it worked
print(type(of: test.$x)) // problem: this is `Binding<Wrap>`, how to access `Binding<Int>` instead?
// in my actual code, I'm using this solution to work with `Color` like this
// `@AppStorage("myColor") @ColorRawRepresentable var color = Color.blue`
// I need to get `Binding<Color>` to pass into `ColorPicker`
Ref: "Should not extend type you don't own with protocol you don't own" is the advice, but - #4 by jrose
@hborla ?
$$x? I think wrapper composition simply uses the markers for each layer of wrapper.
young
(rtSwift)
3
Sorry I forgot to mention, I tried that:
print(type(of: test.$$x)) // Error: Type of expression is ambiguous without more context
Edit: okay, if there is no straight forward answer, then I can just make a Binding manually:
Binding(get: { x }, set: { x = $0 })
I think it should work....
Edit: Yes, it worked:
let binding = Binding {
color
} set: {
color = $0
}
ColorPicker("Color", selection: binding)
jrose
(Jordan Rose)
4
Ah. I think you’ll need to project the binding in that case ($x.wrappedValue). AppStorage doesn’t know about any additional nesting, so it has to vend what it’s given as its generic argument. That’s back to your “manual wrapper struct”, I know, but only in this case.
jrose
(Jordan Rose)
6
Ah, I was hoping it would use the dynamic subscript. You can either invoke that directly or add an alias to Wrap that won’t get shadowed by Binding.
young
(rtSwift)
7
I just manually create a Binding<Color>: