anton
(Anton)
1
Is there a way to create a SwiftUI Binding from a computed property that provides a get {} and set {} shorthand?
Creating bindings for existing read-write properties seems unnessecarily complicated and verbose:
extension UserDefaults {
var isTrackingEnabled: Bool {
get { bool(forKey: "isTrackingEnabled") }
set { set(newValue, forKey: "foo") }
}
}
struct TrackingView: View {
@Binding private var isTrackingEnabled: Bool
init(defaults: UserDefaults) {
self._isTrackingEnabled = Binding(
get: { defaults.isTrackingEnabled },
set: { newValue in defaults.isTrackingEnabled = newValue }
)
}
...
}
I am aware that this specific example is already solved in SwiftUI with the @AppStorage property wrapper, I am rather looking to emulate the same behaviour in general without having to create too much boilerplate.
I am looking to create the following syntax: UserDefaults.standard.$isTrackingEnabled where the property wrapper's projected value can be used as well as the wrapped value but wrapping the property directly is forbidden:
extension UserDefaults {
@Binding var isTrackingEnabled: Bool { // ❌ Non-static property 'isTrackingEnabled' declared inside an extension cannot have a wrapper
Binding(
get: { bool(forKey: "isTrackingEnabled") },
set: { newValue in set(newValue, forKey: "foo") }
)
}
}
Could one create a macro to convert between the two get-set representations?
jlukas
(Jacob Lukas)
2
You probably don’t want to do this, as changes won’t cause your Views to be updated.
ksluder
(Kyle Sluder)
3
@anton’s property wrapper could store an ObservableObject. The property wrapper’s initializer would register for updates from whatever UserDefaults-like storage it’s wrapping and send() the observable object’s objectWillChangePublisher before updating the cached value.
Only in an extension.