IOS NSUserDefaults Наблюдение за изменением значений для одного ключа
У меня есть следующий код, целью которого является захват события изменения NSUserDefaults для определенного ключа.
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:SOME_NSSTRING_VARIABLE
options:NSKeyValueObservingOptionNew
context:NULL];
- (void)observeValueForKeyPath:(NSString *) keyPath ofObject:(id) object change:(NSDictionary *) change context:(void *) context
{NSLog (@"Changed for key %@", keyPath); }
Но watchValueForKeyPath никогда не будет вызван. Я даже попытался заменить SOME_NSSTRING_VARIABLE на строку, указанную в Замечание об изменении значения ключа NSUserDefaults, но это не помогло.
Обновление:
Я изменяю NSUserDefaults из tabview. Вышеприведенный код для мониторинга изменений находится на другой вкладке одного и того же элемента управления tabview. На вкладке, где я отслеживаю изменения (вкладка, где существует код выше), если я добавлю:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// NSLog(@"viewillappear");
NSUserDefaults *FUDefaults = [NSUserDefaults standardUserDefaults];
NSLog(@"The username obtained is: %@", [FUDefaults objectForKey:SOME_NSSTRING_VARIABLE]);
}
обновленное значение NSUserDefaults получается правильно, но watchValueForKeyPath никогда не вызывался.
Ответы
Ответ 1
Изменить: viewDidUnload
теперь устарел, используйте dealloc
вместо removeObserver
Это должно работать отлично, я только что протестировал здесь.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"SomeKey"
options:NSKeyValueObservingOptionNew
context:NULL];
// Testing...
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"test" forKey:@"SomeKey"];
[defaults synchronize];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"SomeKey"];
}
- (void)observeValueForKeyPath:(NSString *) keyPath ofObject:(id) object change:(NSDictionary *) change context:(void *) context
{
if([keyPath isEqual:@"SomeKey"])
{
NSLog(@"SomeKey change: %@", change);
}
}
Вещи, которые вы могли бы проверить.
-
Поместите точку останова в viewDidUnload и убедитесь, что вид не исчезает на вас (поскольку вы меняете SomeKey
на другой viewController). Если это так, то, возможно, переместите свой регистр/код де-региста в init/dealloc в зависимости от того, как работает ваш VC.
-
Использовать явный KeyPath как @"SomeKey"
не подстановку вроде SOME_NSSTRING_VARIABLE
Ответ 2
Версия Swift 3:
override func viewDidLoad() {
super.viewDidLoad()
UserDefaults.standard.addObserver(self, forKeyPath: "keyPath", options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "keyPath" {
//Do something
}
}
deinit {
UserDefaults.standard.removeObserver(self, forKeyPath: "keyPath")
}
Ответ 3
Версия Swift:
func setUserDefaultsListener(){
NSUserDefaults.standardUserDefaults().addObserver(self, forKeyPath: "keyPath", options: NSKeyValueObservingOptions.New, context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "keyPath" {
//Do something
}
}
deinit {
NSUserDefaults.standardUserDefaults().removeObserver(self, forKeyPath: "keyPath")
}
Ответ 4
Версия Swift 5:
extension UserDefaults {
@objc dynamic var keyPath: Int {
return integer(forKey: "keyPath")
}
}
СОВЕТ: убедитесь, что var
точно так же, как keyPath
и где вы используете наблюдателя сделать:
var observer: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
observer = UserDefaults.standard.observe(\.keyPath, options: [.initial, .new], changeHandler: { (defaults, change) in
//Do something
})
}
deinit {
observer?.invalidate()
}