Open ConfusedVorlon opened 4 years ago
update: the wrapper above doesn't work in an ObserveableObject
in that scenario, the best I could see is
class Pref:ObservableObject {
@SwiftyUserDefault(keyPath: \.userLastLoginDate, options: [.observed])
var userLastLoginDate: Date {
willSet {
objectWillChange.send()
}
}
}
And in the multi-document scenario where there isn't a shared prefs object
extension DefaultsKeys {
var magnifyRotation: DefaultsKey<Bool> { .init("magnifyRotation", defaultValue: false) }
}
class Prefs:ObservableObject {
@SwiftyUserDefault(keyPath: \.magnifyRotation, options: [.observed])
var magnifyRotation: Bool {
willSet {
objectWillChange.send()
}
}
var observers:[DefaultsDisposable] = []
init() {
let disposable = Defaults.observe(\.magnifyRotation) { [weak self] (observer) in
self?.objectWillChange.send()
}
observers.append(disposable)
}
deinit {
observers.forEach { (disposable) in
disposable.dispose()
}
}
}
there seems like a lot of boilerplate here
@ConfusedVorlon did you ever resolve this?
I never came up with a good solution that integrated nicely with SwiftyUserDefaults
I played around with this, I think it is possible to do this, following this article by Sundell: https://www.swiftbysundell.com/articles/accessing-a-swift-property-wrappers-enclosing-instance/
I dropped this file into the Pods project: https://gist.github.com/lordzsolt/cf96c5bc4619b2a09d32bce5a5254c27
Then I did:
class SomeViewModel: ObservableObject {
@PublishedUserDefault(keyPath: \.someValue)
var someValue Double
init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
let value = UserDefaults.standard.value(forKey: "someValue") as! Double
UserDefaults.standard.set(value + 1, forKey: "someValue")
DispatchQueue.main.asyncAfter(deadline: .now() + 5) { [self] in
someValue += 1
}
}
}
}
And it seems like it will trigger a redraw of the SwiftUI View each time.
I might try to make a PR with it, but there is a bit too much magic that I don't fully understand. I don't want to break other people's production, until I test it enough myself.
This stuff melts my brain - but I'm really glad you're giving it a go. This would be a great addition to the library.
I had a look at the code, and the thing that strikes me as odd is setting up the observation as a defer in the getter. It seems like that would be more natural in the init.
Perhaps there is some magic going on...
Perhaps there is some magic going on...
Yes, that's what I would've liked to have as well, but I think you only get the enclosing type in the subscript
method
I'm playing with SwiftUI. I was hoping for a property wrapper that would allow me to use the magnificent SwiftyUserDefaults neatly with SwiftUI
Specifically, I'm looking at the case where I can click a button to toggle a setting, and expect the View to update appropriately.
I have had a shot at it. This works, although it doesn't observe changes to the defaults if they're made elsewhere.
I can't see a way to make observation work as the PropertyWrapper seems to need to be a struct rather than a class (so can't hold an observer which may mutate it)
You can test this with
I don't really understand what the mechanisms are here. DynamicProperty is definitely a requirement, but the documentation doesn't give much info about how it 'tells' the View that there has been an update.