ios - KVO 在 iOS 9.3 中损坏

标签 ios objective-c key-value-observing 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);
} 

最佳答案

是的,我也遇到了这个问题,这似乎是一个错误,下面是我目前正在使用的一个快速解决方法,直到这个问题被修复。希望对您有所帮助!

另外要澄清的是,由于 iOS 7 KVO 与 NSUserDefaults 配合得很好,而且它肯定是可观察到的键值,正如 Matt 所说,它在 iOS 9.3 SDK 的 NSUserDefaults.h 中明确写入:“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
        }
    }
}

关于ios - KVO 在 iOS 9.3 中损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36193503/

相关文章:

ios - Swift 向后兼容 iOS 5 的版本

ios - 如果我执行执行验证的 setXXX 方法会发生什么?

ios - 检测对象的至少一个属性是否被修改

ios - Xcode 11 升级 |找不到 iPhone X 模拟器 | XRPackageModel 9.0.omo

ios - 即使在导入 MapKit 后仍使用未声明的类型 'MKMapView'

ios - 将 FetchRequest 项移至其自己的 View 结构后,SwiftUI 停止显示列表更新

ios - 在表格 View 中列出附近的 GeoFire 位置

ios - 在输入另一个单元格后,如何在单元格中启用禁用的文本字段?

ios - 为 UITableView 设置背景图像会占用内存并卡住应用程序

objective-c - 如何告诉(托管)对象通知其 KVO:其属性之一需要重新缓存?