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!")
}
}
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!
Correct Answer:
https://forums.developer.apple.com/message/423512#423512
In the UserDefault extension, the variable name of the @obj dynamic var and the key used in return statement shall be the same.
Another point: we can use a normal variable/constant or a property wrapper like @State, all work.
Thanks!