Cocoa - 如何在NSUserDefaults值更改时进行通知?

53
假设我有一个键为@"MyPreference",对应的值存储在NSUserDefaults中。
是否有一种方法可以在修改该值时得到通知?
或者可以通过绑定来实现吗?(但是,在这种情况下,我希望我的对象能够收到更改的通知,以便我可以执行其他任务。)
我知道可以观察NSUserDefaultsDidChangeNotification,但这似乎是一种全面的方法,并且似乎没有机制可以获取修改的特定键值对。(请随意纠正。)
4个回答

81

花了一整天的时间寻找答案,结果发现在提问后10分钟就找到了...

通过Key-Value-Observing找到了一个解决方案:

[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
    forKeyPath:@"values.MyPreference"
    options:NSKeyValueObservingOptionNew
    context:NULL];

或者更简单地说(根据下面的评论):

[[NSUserDefaults standardUserDefaults] addObserver:self
                                        forKeyPath:@"MyPreference"
                                           options:NSKeyValueObservingOptionNew
                                           context:NULL];

14
你也可以在 [NSUserDefaults standardUserDefaults] 上调用此方法,而无需在键路径前面添加 "values."。其他参数保持不变。 - Quinn Taylor
6
根据 Quin 的建议,我无法使用 [NSUserDefaults standardUserDefaults] 使其正常工作。 然而,字符串追加是不必要的,因为 ...forKeyPath:@"values.MyPreference"... 将可以工作。 另外,您需要实现 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; 来捕获事件。 - TrevorL
1
但这种方法仅适用于Mac,而不适用于iOS。 - M.Y.
NSKeyValueObservingOptionNew选项并非必需。您可以传递0作为选项。 - Flovdis
1
第一个解决方案(使用NSUserDefaultsController)适用于Mac,但第二个解决方案不起作用。 - Ethan
显示剩余3条评论

23

Swift:

override func viewDidLoad() {
  super.viewDidLoad()
  NSUserDefaults.standardUserDefaults().addObserver(self, forKeyPath: "THE KEY", options: NSKeyValueObservingOptions.New, context: nil)
}

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
  // your logic
}

deinit {
  NSUserDefaults.standardUserDefaults().removeObserver(self, forKeyPath: "THE KEY")
}

1
在解释完整个方法后,不要忘记移除观察者。 - slxl

11

8
这样做的缺点是,你无法知道改变了哪个设置。 - Emmanuel
2
是的,你会认为他们至少会把改变的键放在NSUserDefaultsDidChangeNotification的userInfo字典中,但事实并非如此:“此通知不包含userInfo字典。”更糟糕的是,关于何时发布NSUserDefaultsDidChangeNotification的唯一规定是说它是在“更改持久域时”发布的。我可能需要花费20分钟的时间来确认确切的含义,然后我也不确定我会信任它。 - Jerry Krinock
这种方法还有另一个缺点:如果外部程序更改了您的应用程序的默认设置,例如使用cmd“defaults write”或使用Prefs Editor应用程序,则您将不会收到通知。而使用KVO技术则可以通知您。 - Thomas Tempelmann

0

我同意@DenNukem的观点。我一直在使用NSKeyValueObservingOptionNew。但是当我用NSUserDefault来保存其他对象时,此函数开始给我返回BAD_ACCESS Code=1错误。如果您正在使用键值观察器(KVC),请注意NSUserDefaults上的Zombie问题。

以下链接给出了解决方案: NSUserDefaults and KVO issues


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