NSUserDefaults在应用程序关闭/启动后无法持久化。

3

编辑:根据Paul.s的建议更新了代码。

过去一周一直在Stack Overflow上搜寻,但仍然无法让我的应用程序在模拟器和设备中关闭/重新启动应用程序后保持设置更改。

尝试使用Singleton中的NSMutableDictionary,但我不认为这是问题所在。

a)在AppDelegate的applicationDidFinishLaunchingWithOptions中使用registerDefaults为应用程序设置初始默认值:

AppManager *global = [AppManager sharedInstance];


// set up the defaults.
global.gWantFoo = YES;    // This is a BOOL which relates to a UISwitch

// #define kWantFoo @"gWantFoo"
global.globalSettingsDict = [[NSMutableDictionary alloc] 
                               initWithObjectsAndKeys: 
                               [NSNumber numberWithBool:global.gWantFoo], kWantFoo, nil];

global.globalSettings = [NSUserDefaults standardUserDefaults];
[global.globalSettings registerDefaults:global.globalSettingsDict];
[global.globalSettings synchronize];
b) 在 ConfigView 中,我可以设置开关,在开关更改时,我让选择器执行以下操作。
self.global.gWantFoo = NOT(self.global.gWantFoo);   // #define NOT(a)  !(a)
[self.global.globalSettings setBool:self.global.gWantFoo forKey:kWantFoo];
[self.global.globalSettings synchronize];

c) 在applicationDidEnterBackground及其相关方法中,我有一个同步操作。尽管开关值在应用程序实例的生命周期内保持更改,但一旦我重新启动应用程序,gWantFoo就会被默认值"YES"覆盖。

感激任何建议。我几乎要用猛烈的咒骂将我的苹果笔记本电脑扔出窗外了。好吧,在这个编辑过程中我冷静了下来。我觉得轻轻摇晃MacBook Pro可以证明我对NSUserDefaults并不满意 :-)

干杯

sc.


你说你使用了 registerDefaults: - 你是否为 gSettingsAreSet 设置了默认值?如果是这样,那么 [[NSUserDefaults standardUserDefaults] stringForKey:@"gSettingsAreSet"]; 将永远不会返回 nil。另外,为什么这是一个字符串?它似乎是布尔值的完美用例... - Paul.s
嗨,保罗,是的,我也为此设置了默认值。我同意它应该是一个BOOL;这是一些早期调试/模拟尝试的遗留物。我已经切换到使用BOOL,但没有用。我想我需要将所有这些都删除并重新开始。感谢您的回复! - swisscheese
我认为你应该坚持使用registerDefaults:,因为它可以实现你想要的功能。它不会清除NSUserDefaults中保存的信息,只有在没有设置值时才提供默认值... - Paul.s
嗨,保罗,我已经删除并仅使用registerDefaults。很遗憾没有成功。我相信我的问题源于实际更新值-即,我以某种方式错误地使用了setBool:global.gWantFoo forKey:“gWantFoo”。 - swisscheese
2个回答

3

以下是你需要做的/应该发生的事情的完整流程:

application:didFinishLaunchingWithOptions:中,你需要做的第一件事情之一是注册默认值:

NSDictionary *defaultsDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithBool:NO] , PSWantFoo, nil];

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults registerDefaults:defaultsDefaults];

注意:PSWantFoo被定义为NSString * const PSWantFoo = @"PSWantFoo";,因此我不会在代码中到处使用字符串字面值。
如果应用程序从未运行过,则NSLog(@"%d", [defaults boolForKey:PSWantFoo]);将打印0
现在,当我想要设置该值时,我使用类似以下的代码:
[defaults setBool:YES forKey:PSWantFoo];
[defaults synchronize];

现在,当我运行NSLog(@"%d", [defaults boolForKey:PSWantFoo]);时,它将打印1
至于持久性,在此时,因为我已经设置了一个值,所以会为我创建一个plist文件。
<path to app>/Library/Preferences/<bundle identifier>.plist

如果您检查此文件,您将看到类似如下内容:
<?xml version="1.0" encoding="UTF-8"?>
<DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PSWantFoo</key>
    <true/>
</dict>
</plist>

从现在开始,这个值将被读取,而不是在registerDefaults:中注册的值。


更新

为什么你硬编码了这个顺序?

// set up the defaults.
global.gWantFoo = YES;    // This is a BOOL which relates to a UISwitch

为什么不换个思路呢?

将默认值设置为YES进行注册;

NSDictionary *defaultsDefaults = [[NSDictionary alloc] initWithObjectsAndKeys: 
                                   [NSNumber numberWithBool:YES], kWantFoo, nil];

[defaults registerDefaults:defaultsDefaults];

然后在此之后,您可以获得设置。
global.gWantFoo = [defaults boolForKey:kWantFoo];

这种方式可以使应用程序在没有设置偏好设置时回答为,否则将保持应用以前设置的结果。


嗨,保罗,哇——谢谢你提供的全面建议!它给了我重新聚焦的新视角。我已经整合了使用const的干净建议。不知道该怎么告诉你,伙计... :(,我仍然无法使其持久化。我已经阅读了无数教程、iOS书籍等等。很可能是我的编程技巧在这里让我失望了,因为NSUserDefaults的语义显然并不高深,也没有太多内容。无论如何,我会开始一个新项目,只用一个开关,尝试让它工作。顺便说一下,我主要在模拟器上进行测试。再次感谢。 - swisscheese
你和我上面说的有什么不同吗? - Paul.s
我所做的唯一不同之处就是使用了NSMutableDictionary,而在其初始化之前,我会设置global.gWantFoo = YES,以便事先硬编码默认值,这与'[defaults setBool:YES forKey:PSWantFoo];'并没有太大区别。 - swisscheese
发布的代码是否最新?如果不是,您能否提供当前的代码。我不明白global.globalSettingsDict与此有何关系?它与userDefaults无关。那段代码是否执行过?您说过您已经registerDefaults:,这意味着[[NSUserDefaults standardUserDefaults] stringForKey:@"gSettingsAreSet"];永远不会返回nil - Paul.s
嗨伙计,代码已更新。我已删除了最初的是否为空的检查。但是,我认为我必须将该检查放回去,因为gWantFoo的第一个硬编码始终会获胜。 - swisscheese

0

在保存默认值之后,您应该设置标志@"gSettingsAreSet"

[[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"gSettingsAreSet"];
[[NSUserDefaults standardUserDefaults] synchronize];

嗨NeverBe,非常好的建议 - 我现在已经实施了你的建议,谢谢!我成功保存了gWantFoo的状态 :-) 但是,我无法将其设置回YES并使其持久化 - 就像我刚刚解决了我的问题。此时很难看到整个问题的全貌。 - swisscheese
你可以像保存gSettingsAreSet一样保存gWantFoo。 - NeverBe

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