NSUserDefaultsDidChangeNotification:密钥的名称是什么,改变了什么?

时间:2012-06-03 16:08:19

标签: objective-c ios xcode nsuserdefaults nsnotificationcenter

当UserDefaults中的某些值发生变化时,此代码将调用方法“defaultsChanged”

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
           selector:@selector(defaultsChanged:)  
               name:NSUserDefaultsDidChangeNotification
             object:nil];

此代码将为我提供更改的值

- (void)defaultsChanged:(NSNotification *)notification {
    // Get the user defaults
    NSUserDefaults *defaults = (NSUserDefaults *)[notification object];

    // Do something with it
    NSLog(@"%@", [defaults objectForKey:@"nameOfThingIAmInterestedIn"]);
}

但是如何获得密钥的名称,改变了?

5 个答案:

答案 0 :(得分:29)

正如其他人所述,无法从NSUserDefaultsDidChange通知中获取有关已更改密钥的信息。但是没有必要复制任何内容并自行检查,因为键值观察(KVO)也适用于NSUserDefaults,如果您需要具体是已通知某个属性

首先,注册KVO而不是使用NotificationCenter:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults addObserver:self
           forKeyPath:@"nameOfThingIAmInterestedIn"
              options:NSKeyValueObservingOptionNew
              context:NULL];

不要忘记删除观察(例如在viewDidUnload或dealloc中)

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults removeObserver:self forKeyPath:@"nameOfThingIAmInterestedIn"];

最后实现此方法以接收KVO通知

-(void)observeValueForKeyPath:(NSString *)keyPath 
                 ofObject:(id)object
                   change:(NSDictionary *)change
                  context:(void *)context 
{
    NSLog(@"KVO: %@ changed property %@ to value %@", object, keyPath, change);
}

答案 1 :(得分:2)

通知的userInfo字典中没有提供数据,所以看起来你运气不好,除非你想在其他地方保存NSUserDefaults存储的数据的另一个副本并执行差异在两本词典上。

答案 2 :(得分:1)

使用自定义通知来确定究竟发生了什么,例如:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:self.event, @"eventObject", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"newEventCreated" object:nil userInfo:options];

如果它不是userDefaults的选项,那么只要在每次收到NSUserDefaultsDidChangeNotification通知时读取所有用户默认值,并将其与以前的通知进行比较。

答案 3 :(得分:1)

只需添加[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:nil];

到您的appDidBecomeActive方法,然后添加

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(settingsChangedListener) name:NSUserDefaultsDidChangeNotification object:nil];

applicationDidEnterBackground

然后在前景

时使用如上所示的KVO观察者

答案 4 :(得分:-1)

您可以使用dictionaryRepresentation获取NSUserDefaults的完整副本NSDictionary。然后是比较先前的值和新值。

NSUserDefaults不符合KVO标准,不应该依赖它可以触发一些KVO通知这一事实,并且显然会发生变化。

例如:

- (void)setupUserDefaults {
    self.userDefaults = [NSUserDefaults standardUserDefaults];
    [self.userDefaults registerDefaults:@{ /* ... */ }];

    self.userDefaultsDictionaryRepresentation = [self.userDefaults dictionaryRepresentation];

    [notificationCenter addObserver:self 
                           selector:@selector(userDefaultsDidChange:) 
                               name:NSUserDefaultsDidChangeNotification 
                             object:self.userDefaults];
}

- (void)userDefaultsDidChange:(NSNotification *)note {
    NSDictionary *oldValues = self.userDefaultsDictionaryRepresentation;
    NSDictionary *newValues = [self.userDefaults dictionaryRepresentation];

    NSArray *allKeys = @[ /* list keys that you use */ ];

    for(NSString *key in allKeys) {
        id oldValue = oldValues[key];
        id newValue = newValues[key];

        if(![oldValue isEqual:newValue]) {
            [self notifyObserversForKeyChange:key oldValue:oldValue newValue:newValue];
        }
    }

    self.userDefaultsDictionaryRepresentation = newValues;
}