KVO在iOS 9.3中被破坏了

Mat*_*att 7 objective-c key-value-observing ios ios9.3

这可能是iOS 9.3(发布)中的一个糟糕的错误.

添加单个观察者时,[NSUserDefaults standardUserDefaults]我注意到响应方法-observeValueForKeyPath:ofObject:change:context:被多次调用.

在下面的简单示例中,每次按下一次UIButton时,observeValueForKeyPath会触发两次.在更复杂的例子中,它会发射更多次.它仅出现在iOS 9.3上(包括sim和设备).

这显然会对应用程序造成严重破坏.其他人经历过同样的事情吗?

// 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);
} 
Run Code Online (Sandbox Code Playgroud)

小智 5

是的我也遇到了这个问题,它似乎是一个错误,下面是我正在使用的快速解决方法,直到这个问题得到解决.我希望它有所帮助!

另外要澄清一下,因为iOS 7 KVO在NSUserDefaults上工作得非常好,并且它看起来像Matt所说的那样具有关键的值可观察性,它在iOS 9.3 SDK中用NSUserDefaults.h明确写出:"可以使用Key-Value观察NSUserDefaults观察存储在其中的任何密钥."

#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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)