如何使用NSUserDefaults注册用户默认值而不覆盖现有值?

34

我有一个AppDelegate类,其中包含+(void)initialize方法,我使用它来注册一些默认值。这是我使用的代码:


我有一个AppDelegate类,其中包含+(void)initialize方法,我使用它来注册一些默认值。这是我使用的代码:
+ (void)initialize {
  NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:@"NO", @"fooKey", @"YES", @"barKey", nil];

  [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
}

我还创建了一个 Preferences.xib,其中包含几个复选框 (NSButton),显示偏好设置的状态。它们与 NSUserDefaultsController 绑定到相同的键 (在此情况下是fooKey和barKey)。每次启动应用程序并更改“defaults”后,它们会在下次启动应用程序时恢复。

有没有办法注册“默认默认值”,而不覆盖已经存在的值?也许每次构建和启动应用程序时,它的偏好文件都会被重新创建?也许我应该取消复选框与NSUserDefaultsController的绑定,并通过一些自定义代码在偏好窗口控制器中自己维护键的值?

我想听听您的用户偏好设置维护实现选择。

我正在使用 Mac OS X 10.6.2 和 XCode 3.2.1


请确保复选框绑定到“Shared User Defaults Controller”,控制器键“values”,模型键路径“fooKey”/“barKey”。否则,您的代码看起来没问题。 - Costique
5
@"NO" 不是布尔字面值,它是表示单词“NO”的字符串字面值。你应该使用[NSNumber numberWithBool:NO],否则在用户默认设置中的值将不是布尔类型。 - Peter Hosey
不,它们不会被这样读取,但如果我将它们读取为BOOLs - 它们就会被这样读取。这是来自Daniel H Steinberg的书《Cocoa Programming》(pragprog.com)的摘录:实际上,在将BOOL放入字典中时,您不需要如此明确。您可以将值YES或NO作为字符串传递,并在从首选项读取时仍然从该值创建BOOL。 - Eimantas
1
请注意,+ (void)initialize 的实现应始终以 if (self != [YourClass class]) { return; } 开头,否则如果您的子类未实现自己的 + (void)initialize 方法,则会被调用多次。还要记住使用 [YourClass class] 而不是 [self class]。(这是其中一个正确调用类自己方法的地方之一)。所有这些都是因为运行时以特殊方式处理 + (void)initialize:没有重载。每个类都会调用其实现(或超类的实现,如果没有提供)。 - Regexident
1个回答

75

-registerDefaults:的文档中(重点加粗):

注册域的内容不会写入磁盘;您需要每次启动应用程序时调用此方法。您可以在应用程序的资源目录中放置一个plist文件,并使用从该文件中读取的内容调用registerDefaults:

所以你的代码走在了正确的轨道上。这是注册默认值的方法。

我通常在-applicationDidFinishLaunching:中使用它:

// Load default defaults
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Defaults" ofType:@"plist"]]];

使用 plist 可以轻松添加和更改应用程序中的默认值,并防止您错误地使用 @"NO" 作为值。

编辑:Swift 3 变体:

 UserDefaults.standard.register(defaults: NSDictionary(contentsOf: Bundle.main.url(forResource: "Defaults", withExtension: "plist")!)! as! [String : Any])

是的,尽管您的设置包可能在应用程序启动之前就已加载,因此您仍然可能希望在设置plist中设置初始默认值。-registerDefaults:方法不会覆盖通过设置包设置的首选项。 - Johan Kool
2
由于某种原因,当我将它放在-applicationWillFinishLaunching中时,它没有起作用。只需将其移动到-applicationDidFinishLaunching中即可解决问题。奇怪。 - geerlingguy
@JohanKool 如果 registerDefaults 不写入磁盘,为什么我要使用它?我可以自己保留从 Bundle plist 获取的字典。 - onmyway133
它对我不起作用 :( 我使用了@"Settings.bundle/Root"而不是@"Defaults"。这样正确吗? - Charles
作为解决方法,我使用了在此定义的registerDefaultsFromSettingsBundle函数:http://ijure.org/wp/archives/179 - Charles
显示剩余2条评论

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