NSUserDefaultsDidChangeNotification:更改的密钥的名称是什么?

问题描述 投票:0回答:6

当 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"]);
}

但是我怎样才能获得更改后的密钥的名称??

ios objective-c nsuserdefaults nsnotificationcenter
6个回答
32
投票

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

首先,注册 KVO 而不是使用通知中心:

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

2
投票

通知的

userInfo
字典中没有提供数据,因此看起来您运气不好,除非您想在其他地方保留存储在
NSUserDefaults
中的数据的另一个副本,并对两个字典执行比较。


1
投票

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

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

如果它不是 userDefaults 的选项,则只需在每次收到

NSUserDefaultsDidChangeNotification
通知时阅读所有用户默认值,并将其与之前的通知进行比较。


1
投票

只需添加

[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:nil];

到您的

appDidBecomeActive
方法,然后添加

[

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

致你的

applicationDidEnterBackground

然后在前台使用 KVO 观察器,如上所示


0
投票

如果您的 plist 对于“之前”-“之后”匹配来说太大,并且您只是不想向所有现有键添加特定的观察者(仍然错过新创建的键),您也可以混合 setObject:forKey :-NSUserdefaults 中的方法。

代码可能看起来像这样(TODO:错误对象应该正确处理!)

#import "NSUserDefaults+MacOS.h"
#import "JRSwizzle.h"


@implementation NSUserDefaults (MacOS)


+ (void)load {
    [NSUserDefaults jr_swizzleMethod:@selector(setObject:forKey:) withMethod:@selector(zs_setObject:forKey:) error:nil];
    [NSUserDefaults jr_swizzleMethod:@selector(removeObjectForKey:) withMethod:@selector(zs_removeObjectForKey:) error:nil];
}

- (void) zs_setObject:(id)value forKey:(NSString *)key {
    NSObject* oldValue = [[NSUserDefaults standardUserDefaults] valueForKey:key];
    [self zs_setObject:value forKey:key];
    NSObject* newValue = [[NSUserDefaults standardUserDefaults] valueForKey:key];
    [[ZSplistWatcher sharedInstance] defaultsChangedForKey:key oldValue:oldValue newValue:newValue];
}


- (void) zs_removeObjectForKey:(NSString *)key {
    NSObject* oldValue = [[NSUserDefaults standardUserDefaults] valueForKey:key];
    [self zs_removeObjectForKey:key];
    [[ZSplistWatcher sharedInstance] defaultsChangedForKey:key oldValue:oldValue newValue:nil];
}

@end

(ZSplistWatcher-Part只是一个示例代码,用于通知其他对象更改。请根据您的需要进行调整)


-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;
}
© www.soinside.com 2019 - 2024. All rights reserved.