I am trying to implement UserDefaults class using @propertyWrapper
. What I am trying to do is creating a wrapper class for my app user preferences. So I wrote following code.
@propertyWrapper
struct Storage<T> {
private let key: String
private let defaultValue: T
var projectedValue: Storage<T> { return self }
var wrappedValue: T {
get {
return UserDefaults.standard.string(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
func observe(change: @escaping (T?, T?) -> Void) -> NSObject {
return DefaultsObservation(key: key) { old, new in
change(old as? T, new as? T)
}
}
}
Then, I'd like to observe UserDefaults value changes. So I implemented an observation class named DefaultsObservation
.
class DefaultsObservation: NSObject {
let key: String
private var onChange: (Any, Any) -> Void
init(key: String, onChange: @escaping (Any, Any) -> Void) {
self.onChange = onChange
self.key = key
super.init()
UserDefaults.standard.addObserver(self, forKeyPath: key, options: [.old, .new], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
guard let change = change, object != nil, keyPath == key else { return }
onChange(change[.oldKey] as Any, change[.newKey] as Any)
}
deinit {
UserDefaults.standard.removeObserver(self, forKeyPath: key, context: nil)
}
}
Also my AppData class is following.
struct AppData {
@Storage(key: "layout_key", defaultValue: "list")
static var layout: String
}
However, when I tried to add and listen changes layout
property it is not working properly.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppData.$layout.observe { old, new in
print(old)
}
}
When I debugged it, deinit
is working as soon as viewWillAppear
method invoked. When I commented out deinit
method for removing observer everything is working perfect. I think closing deinit
can cause some memory problems. So I do not want to commented it out. What am I missing and how can I solve it?