当 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"]);
}
但是我怎样才能获得更改后的密钥的名称??
正如其他人所说,无法从 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);
}
通知的
userInfo
字典中没有提供数据,因此看起来您运气不好,除非您想在其他地方保留存储在 NSUserDefaults
中的数据的另一个副本,并对两个字典执行比较。
使用自定义通知来确定到底发生了什么,例如:
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:self.event, @"eventObject", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"newEventCreated" object:nil userInfo:options];
如果它不是 userDefaults 的选项,则只需在每次收到
NSUserDefaultsDidChangeNotification
通知时阅读所有用户默认值,并将其与之前的通知进行比较。
只需添加
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:nil];
到您的
appDidBecomeActive
方法,然后添加
[
[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(settingsChangedListener) name:NSUserDefaultsDidChangeNotification object:nil];
致你的
applicationDidEnterBackground
然后在前台使用 KVO 观察器,如上所示
如果您的 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只是一个示例代码,用于通知其他对象更改。请根据您的需要进行调整)
您可以使用
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;
}