我刚刚被烧毁,因为我的iOS应用程序的更新在App Store上发布,不幸的是,由于我的代码使用NSUserDefaults
方式的错误,它在使用新功能时崩溃了。我的应用使用registerDefaults
,但新功能会尝试写入升级后不存在的密钥。如果从头开始安装,它可以正常工作,因为密钥是由registerDefaults
创建的。
具体来说,我的应用程序使用嵌套字典,因此在更新之前,首选项文件具有以下结构:
<dict>
<key>Alpha</key>
<dict>
<key>Key</key>
<string>Value</string>
</dict>
<key>Beta</key>
<dict>
<key>Key</key>
<string>Value</string>
</dict>
<key>Charlie</key>
<dict>
<key>Key</key>
<string>Value</string>
</dict>
</dict>
- 更新后,需要键 Delta :
<dict>
<key>Alpha</key>
<dict>
<key>Key</key>
<string>Value</string>
</dict>
<key>Beta</key>
<dict>
<key>Key</key>
<string>Value</string>
</dict>
<key>Charlie</key>
<dict>
<key>Key</key>
<string>Value</string>
</dict>
<key>Delta</key>
<dict>
<key>Key</key>
<string>Value</string>
</dict>
</dict>
当我的代码尝试从用户默认值中检索 Delta 的字典时,我的代码正在倒下,以便为其写入一些键和值。对于这种情况,字典为nil
,因为更新后它不在首选项文件中。
处理这种情况的最佳做法是什么?我是否应该在尝试写入 Delta 之前检查 Delta 的字典是否为nil
,并在需要时创建它,或者是否有更少的腰带和括号方法?
答案 0 :(得分:1)
我遵循以避免这些情况的模式如下:
在我的ApplicationDelegate +(void)initialize
方法中,我设置了密钥及其默认值,以确保在设置之前没有尝试触摸默认值:
+(void)initialize
{
NSDictionary *factoryPrefs = @{MyNewPrefKey:@"ANewPrefKeyDefaultValue"};
}
[[NSUserDefaults standardUserDefaults] registerDefaults:factoryPrefs];
userSettings = [NSUserDefaults standardUserDefaults];
接下来,在此之后,我有一个基于当前版本的代码块,开始检查是否存在暗示用户正在升级(不是新的)的先前值。在那种情况下,我将不得不迁移/更新prefs。
例如,有时必须更改键或插入值,就像在某些先前版本中存储了值为a,b,c的NSDictionary对象一样,但现在在此版本中。你依赖(并假设)'d'值也在那里。
在这种情况下,registerDefaults
无法提供帮助,因为您注意到之前创建的值。所以你必须手动检查'd'是否在那里,如果不插入它与默认值。这是Prefs的CoreData迁移等价物:)
这就是我的工作。我是虔诚地做的。我检查它每次发布,因为...我被烧了,就像你以前做的那样。然后我们都知道接下来会发生什么,你会得到一个认真的1星...在App Store中呐喊。
答案 1 :(得分:1)
我对您的数据做了一个简单的测试:
将defaults.plist文件添加到空项目中;
将defaults.plist设置为包含Alpha / Beta / Charlie键(根据您的示例);
在appDidFinishLaunching时使用以下代码:
NSString* path = [[NSBundle mainBundle] pathForResource:@"defaults" ofType:@"plist"];
NSDictionary* factoryPrefs = [NSMutableDictionary dictionaryWithContentsOfFile:path];
[[NSUserDefaults standardUserDefaults] registerDefaults:factoryPrefs];
NSLog(@"Delta Key: %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"Delta"]);
//-- store some user custom values
NSLog(@"Charlie Key %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"Charlie"]);
[[NSUserDefaults standardUserDefaults] setObject:@"test" forKey:@"Charlie"];
NSLog(@"Charlie Key %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"Charlie"]);
运行应用程序;
结果是:
2013-02-23 17:59:10.795 JigSaw[14747:c07] Delta Key (null)
2013-02-23 17:59:10.797 JigSaw[14747:c07] Charlie Key {
Key = Value;
}
2013-02-23 17:59:10.797 JigSaw[14747:c07] Charlie Key test
然后,我通过添加Delta键(再次,根据您的示例)更改了defaults.plist的内容,并再次构建/运行应用程序(当然,不从设备中删除它)。
结果是:
2013-02-23 18:00:37.840 JigSaw[15040:c07] Delta Key {
Key = Value;
}
2013-02-23 18:00:37.842 JigSaw[15040:c07] Charlie Key test
2013-02-23 18:00:37.842 JigSaw[15040:c07] Charlie Key test
因此,registerDefaults
似乎会在使用时正确处理任何新添加的密钥,如上例所示。
我倾向于认为您错误地使用registerDefaults
,或者您正在其他地方执行导致崩溃的原因。
在更一般的层面上,除了测试应用程序更新方案(事后很容易建议,而且我们都以某种方式学习它),对我来说,良好的做法是我确保即使存在错误或无法预料的输入,您的应用也不会崩溃。