IOS NSUserDefaults Monitoring Changes in Values โ€‹โ€‹for a Single Key

I have the following code whose purpose is to capture the NSUserDefaults change event for a specific key.

[[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); } 

But watchValueForKeyPath will never be called. I even tried replacing SOME_NSSTRING_VARIABLE with the line specified in the Note about changing the NSUserDefaults key value , but that did not help.

Update: I am modifying NSUserDefaults from tabview. The above code for monitoring changes is on a different tab of the same tabview control. On the tab where I track changes (the tab where the code above exists), if I add:

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // NSLog(@"viewillappear"); NSUserDefaults *FUDefaults = [NSUserDefaults standardUserDefaults]; NSLog(@"The username obtained is: %@", [FUDefaults objectForKey:SOME_NSSTRING_VARIABLE]); } 

the updated NSUserDefaults value is obtained correctly, but watchValueForKeyPath has never been called.

+13
ios nsuserdefaults
source share
4 answers

Edit: viewDidUnload now deprecated, use dealloc instead of removeObserver

This should work just fine, I just tested here.

 - (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); } } 

Things you could check out.

  • Put a breakpoint in viewDidUnload and make sure the view does not disappear on you (since you are changing SomeKey to another viewController). If so, then maybe move your register / de-register code to init / dealloc depending on how your VC works.

  • Using explicit KeyPath as @"SomeKey" not a wildcard like SOME_NSSTRING_VARIABLE

+25
source share

Swift 3 version:

 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") } 
+8
source share

Swift Version:

 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") } 
+3
source share

Swift 5 Version:

 extension UserDefaults { @objc dynamic var keyPath: Int { return integer(forKey: "keyPath") } } 

TIP: make sure var exactly the same as keyPath

and where do you use the observer to do:

 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() } 
0
source share

All Articles