This might be an awful bug in iOS 9.3 (release).
When adding a single observer to [NSUserDefaults standardUserDefaults]
I've noticed that the responding method -observeValueForKeyPath:ofObject:change:context:
is called multiple times.
In the simple example below, every time a UIButton is pressed once, observeValueForKeyPath fires twice. In more complicated examples it fires even more times. It is only present on iOS 9.3 (both on sim and devices).
This can obviously wreak havoc on an app. Anyone else experiencing the same?
// ViewController.m (barebones, single view app)
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"viewDidLoad");
[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"SomeKey" options:NSKeyValueObservingOptionNew context:NULL];
}
- (IBAction)buttonPressed:(id)sender {
NSLog(@"buttonPressed");
[[NSUserDefaults standardUserDefaults] setInteger:1 forKey:@"SomeKey"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
NSLog(@"observeValueForKeyPath: %@", keyPath);
}
Yes I am experiencing this as well and it seems to be a bug, below is a quick workaround I’m using for the moment until this is fixed. I hope it helps!
Also to clarify, since iOS 7 KVO has been working great with NSUserDefaults and it certainly appears to be key value observable as Matt stated, it is explicitly written in NSUserDefaults.h in the iOS 9.3 SDK: “NSUserDefaults can be observed using Key-Value Observing for any key stored in it."
#include <mach/mach.h>
#include <mach/mach_time.h>
@property uint64_t newTime;
@property uint64_t previousTime;
@property NSString *previousKeyPath;
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
//Workaround for possible bug in iOS 9.3 SDK that is causing observeValueForKeyPath to be called multiple times.
newTime = mach_absolute_time();
NSLog(@"newTime:%llu", newTime);
NSLog(@"previousTime:%llu", previousTime);
//Try to avoid duplicate calls
if (newTime > (previousTime + 5000000.0) || ![keyPath isEqualToString:previousKeyPath]) {
if (newTime > (previousTime + 5000000.0)) {
NSLog(@"newTime > previousTime");
previousTime = newTime;
NSLog(@"newTime:%llu", newTime);
NSLog(@"previousTime:%llu", previousTime);
}
if (![keyPath isEqualToString:previousKeyPath]) {
NSLog(@"new keyPath:%@", keyPath);
previousKeyPath = keyPath;
NSLog(@"previousKeyPath is now:%@", previousKeyPath);
}
//Proceed with handling changes
if ([keyPath isEqualToString:@“MyKey"]) {
//Do something
}
}
}
When adding a single observer to
[NSUserDefaults standardUserDefaults]
I've noticed that the responding method-observeValueForKeyPath:ofObject:change:context:
is called multiple times
This is a known issue and is reported (by Apple) as fixed in iOS 11 and macOS 10.13.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With