Cocoa-NSUserDefaults值更改通知?

Cocoa-NSUserDefaults值更改通知?,cocoa,notifications,preferences,Cocoa,Notifications,Preferences,假设我有一个键@“MyPreference”,对应的值通过NSUserDefaults存储 是否有一种方法可以在值被修改时得到通知 或者可以通过绑定来完成吗?(但在这种情况下,我不希望将值绑定到UI元素,而是希望将更改通知给我的对象,以便我可以执行其他任务。) 我知道可以观察到nsUserDefaultsIDChangeNotification,但这似乎是一种要么全有要么全无的方法,而且似乎没有一种机制可以获取已修改的特定键值对。(请随意更正。)花了一整天寻找答案,但在提出问题10分钟后才找到答

假设我有一个键
@“MyPreference”
,对应的值通过
NSUserDefaults
存储

是否有一种方法可以在值被修改时得到通知

或者可以通过绑定来完成吗?(但在这种情况下,我不希望将值绑定到UI元素,而是希望将更改通知给我的对象,以便我可以执行其他任务。)


我知道可以观察到
nsUserDefaultsIDChangeNotification
,但这似乎是一种要么全有要么全无的方法,而且似乎没有一种机制可以获取已修改的特定键值对。(请随意更正。)

花了一整天寻找答案,但在提出问题10分钟后才找到答案

通过关键价值观察发现了解决方案:

[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
    forKeyPath:@"values.MyPreference"
    options:NSKeyValueObservingOptionNew
    context:NULL];
或者,更简单地说(根据下面的评论):


苹果员工建议在此处使用NSUserDefaultsIDChangeNotification通知:

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")
}
override func viewDidLoad(){
super.viewDidLoad()
NSUserDefaults.standardUserDefaults().addObserver(self,forKeyPath:“键”,选项:NSKeyValueObservingOptions.New,上下文:nil)
}
重写func observeValueForKeyPath(键路径:字符串,对象对象:AnyObject,更改:[NSObject:AnyObject],上下文:UnsafeMutablePointer){
//你的逻辑
}
脱硝{
NSUserDefaults.standardUserDefaults().removeObserver(self,forKeyPath:“键”)
}

我同意@DenNukem的观点。我正在使用NSKeyValueObservingOptionNew。但是当我使用
NSUserDefault
保存其他对象时,该函数开始向我提供
BAD\u ACCESS code=1
错误。如果您使用的是Key-Value Observer(KVC),请注意
NSUserDefaults
上的僵尸问题

以下是解决方案的链接:

您也可以在
[NSUserDefaults standardUserDefaults]
上调用此方法,而不必将“值”前置到键路径。其他参数保持不变。我无法使用
[NSUserDefaults standardUserDefaults]
让它按照Quin的建议工作。但是,不需要字符串append,因为
…forKeyPath:@“values.MyPreference”…
可以工作。此外,您还需要实现对象的键路径:(id)对象更改:(NSDictionary*)更改上下文:(void*)上下文以实际捕获事件。Hi TrevorL…尽管stringByAppendingString:不是必需的,但它在创建泛型方法时会有所帮助-(void)observePreference:(NSString*)pref{…[@”值。“stringByAppendingString:pref]”…但这种方法仅适用于Mac,而不是第一种解决方案(使用
NSUserDefaultsController
)适用于Mac,但第二种解决方案不起作用。其缺点是,您无法知道更改了哪些设置。是的,您可能认为他们至少会将更改的密钥放入NSUserDefaultsDidChangeNotification的userInfo字典中,但否:“此通知不包含userInfo字典。”更糟糕的是,NSUserDefaultsDidChangeNotification何时发布的唯一规范说,它是在“持久域发生更改时”发布的。我可能需要20分钟的研究才能确认这到底意味着什么,然后我不确定我是否会相信它。这种方法还有另一个缺点:如果外部程序更改了你的应用程序的默认值,例如使用cmd“defaults write”或者使用Prefs Editor应用程序,则不会通知您。使用KVO技术会通知您,OTOH。不要忘记删除observer,因为您正在解释完整的方法
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")
}