NSUserDefaults和KVO问题

10

我在我的应用程序中使用NSUserDefaults,我想在特定的值被更改时得到通知。 为此,我在viewDidLoad中添加了以下行:

NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
[settings synchronize];
[settings addObserver:self forKeyPath:@"pref_server" options:NSKeyValueObservingOptionNew context:NULL];

并且通知的方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{

    NSLog(@"Change");

    NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
    if (object == settings && [keyPath isEqualToString:@"pref_server"])
    {
        NSLog(@"Server did change");
    }

}

不幸的是,后者从未被调用... @“pref_server”是我在Settings.bundle中设置的Root.plist中的项目标识符。我做错了什么?


有点离题的是,synchronise() 的文档声明:“等待默认数据库的所有待处理异步更新完成后返回。该方法是不必要的,不应被使用。” - Yunus Nedim Mehel
如果遇到问题,请查看NSUserdefaults的一位作者撰写的非常详细的博客文章:http://dscoder.com/defaults.html - Thomas Tempelmann
5个回答

19

我建议使用适当的通知:NSUserDefaultsDidChangeNotification

在Xcode中的苹果文档中搜索AppPrefs,它会显示一个示例应用程序,该应用程序正是您想要做的。只需编译和运行!它使用了NSUserDefaultsDidChangeNotification

这是用于注册观察者的代码:

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

对于Swift3:NotificationCenter.default.addObserver(self, selector: #selector(defaultsChanged), name: UserDefaults.didChangeNotification, object: nil) - Yohst
1
如果更改发生在另一个进程中,则不会发送通知,因此KVO是检查主应用程序和其扩展(今天小部件等)之间共享的NSUserDefaults键值的更改的唯一方法。 - valeCocoa

8

有趣的观察结果:

[NSUserDefaults standardUserDefaults] 现在似乎是 KVO 兼容的,因为我能够观察和绑定它的值。我使用的是 Xcode 4.2,SDK 10.7,LLVM 编译器 3.0,运行的系统版本是 10.7.2。

我似乎找不到关于这个新行为的任何发布说明的文档。


1
我猜这是Lion中一个未记录的更改。发布说明提到了对默认值进行的一些底层更改,因此我猜KVO支持也在同一时间发生了变化。在Cocoa绑定编程主题中,Snow Leopard和Lion都记录了需要使用控制器来进行KVC / KVO的操作。 - Mark Lilback
3
这个问题特别涉及到[ios]标签。 - Ben Collins
文档说明它是兼容的:“...您可以使用键值观察来通知特定默认值的任何更新...”:developer.apple.com/documentation/foundation/userdefaults - Yunus Nedim Mehel

3

NSUserDefaults不符合KVO规范,但是NSUserDefaultsController符合。因此你可以使用:

NSUserDefaultsController *defaultsc = [NSUserDefaultsController sharedUserDefaultsController];
[defaultsc addObserver:self forKeyPath:@"values.pref_server" 
               options:NSKeyValueObservingOptionNew 
               context:NULL];

12
NSUserDefaultsController在iOS的Cocoa Touch中不可用。 - Yang Meyer
1
文档说明它是兼容的:“...您可以使用键值观察来通知任何特定默认值的更新...” https://developer.apple.com/documentation/foundation/userdefaults - Yunus Nedim Mehel

3
尽管文档不够完善,但NSUserDefaults在iOS7中支持键值观察。

2

从iOS 11.3开始,这个功能可以使用并有文档记录:

响应默认更改

您可以使用键值观察来通知特定默认值的任何更新。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接