UserDefaults.publisher works really well in UIKit, and even Apple's documentation mainly revolves around that. However, I'm unable to get the desired behaviour of continous observing of values using UserDefaults.publisher in SwiftUI.
Example UIKit Code that works perfectly:
import UIKit
import Combine
extension UserDefaults {
@objc dynamic var test: Int {
return integer(forKey: "test")
}
}
class ViewController: UIViewController {
var subscriber: AnyCancellable? // Subscriber of preference changes.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
subscriber = UserDefaults.standard
.publisher(for: \.test)
.sink() {
print($0)
}
UserDefaults.standard.set(5, forKey: "test")
UserDefaults.standard.set(10, forKey: "test")
UserDefaults.standard.set(100, forKey: "test")
}
}
Output of above code:
[initial value]
5
10
100
Problematic SwiftUI code:
import SwiftUI
import Combine
extension UserDefaults {
@objc dynamic var userValue: Int {
return integer(forKey: "value")
}
}
struct ContentView: View {
// @ObservedObject var auth = AuthModel()
@State var cancellable: AnyCancellable? = UserDefaults.standard
.publisher(for: \.userValue)
.sink() {
print($0)
}
var body: some View {
Text("hello!")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Output: prints the value stored once, however, after that, it doesn't reprints the values automatically on changes.
I've tried using a separate Model class, but the issue stays and the core reason remains the same I guess.
Any help would be greatly appreciated, thanks!
Thanks for updating your code. And I can confirm that your updated UIKit code works as you describe.
The reason these changes fix the issue is because `publisher(for:)` is a method for NSObject and works with KVO-compliant properties.
UserDefaults works as KVO-compliant for the keys specified in `set(_:forKey:)`.
So, if you want to obseve updates made with `set(..., forKey: "test")`, you need to observe on the ObjC key path "test".
Please apply the same fix to your SwiftUI code and see what happens.
If it still shows unexpected behavior, please show whole updated code including the code which sets value to UserDefaults.