I am working on an iOS app which has a watchOS app as well. I have a settings bundle so when some settings is changed in the iPhone's settings application, the userdefaults of the app will be changed. And whenever a userdefault is updated, I need to send that to the watch app through watch connectivity.
For sending it to watch, I would need to know if a userdefault value is updated. I went through a lot of articles but nothing seems to be working out in my case.
The property wrapper @AppStorage is good if I need to listen for a userdefault and update a view. But thats not my case. I don't need to update a view. I need to know the change in userdefault and pass it on to watch.
I created a swift class with the following code,
import Foundation
import Combine
class UserDefaultsHelper: ObservableObject {
@Published var settings1: String = UserDefaults.standard.settings1 {
didSet {
UserDefaults.standard.settings1 = settings1
}
}
@Published var settings2: String = UserDefaults.standard.settings2 {
didSet {
UserDefaults.standard.settings2 = settings2
}
}
private var cancellable: AnyCancellable?
init() {
cancellable = UserDefaults.standard.publisher(for: \.settings1)
.sink(receiveValue: { [weak self] newValue in
guard let self = self else { return }
if newValue != self.settings1 { // avoid cycling !!
self.settings1 = newValue
}
})
cancellable = UserDefaults.standard.publisher(for: \.settings2)
.sink(receiveValue: { [weak self] newValue in
guard let self = self else { return }
if newValue != self.settings2 { // avoid cycling !!
self.settings2 = newValue
}
})
}
}
// define key for observing
extension UserDefaults {
@objc dynamic var settings1: String {
get { string(forKey: "settings1") ?? "DEFAULT_VALUE" }
set { setValue(newValue, forKey: "settings1") }
}
@objc dynamic var settings2: String {
get { string(forKey: "settings2") ?? "DEFAULT_VALUE" }
set { setValue(newValue, forKey: "settings2") }
}
}
But the problem is, I am not sure where should i call this class from. If I call from the content view, I get the error
Static method 'buildBlock' requires that 'UserDefaultsHelper' conform to 'View'.
So what is the right way to do this. The requirement is to observe the userdefaults and then a call a method in the WatchConnectivity class to pass it on to the watch.