NSUserDefaults数据丢失的现象及初步的解决方案

最近在iOS的APP开发过程中,发现NSUserDefaults在设备重启后,可能会出现lost data现象,就是存储到NSUserDefaults 中的数据,却读取不到

这个现象会导致APP出现奇怪的现象,明明是已经登录过或全用过的APP,在某次启动后会发现好像是重新安装的APP一样,这是因为所有NSUserDefaults中存储的数据丢失

经过GOOGLE,发现在Apple官方论坛中也有人汇报过此问题,此问题很可能是Apple的iOS系统级BUG

访问NSUserDefaults数据丢失以获取详情

经过思考,决定在didFinishLaunchingWithOptions 方法中做一次检查,逻辑是:

  1. 第一次APP启动时,写入一个固定的文件名及一个固定的

NSUserDefaults值

  1. 后面每次启动进入app时,尝试检查固定的文件是否存在,如果存在,则检查NSUserDefaults中固定值是否能读取到
  2. 如果无法读取到,说明遇到此问题,尝试进行修复,修复方法是 1) 重置NSUserDefaults 2) 多次重置后读取不到,强行闪退

由于这种现象出现后,在KILL进程后,很可能不会再次出现,因此在不得已的情况下,KILL进程重来,都好过进去发现数据被清空的感觉一样

代码参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
-(void)loadAndCheckUserDefault{

NSString* checkFilePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingString:@".workplus"];
NSString* checkKey = @"WORKPLUS_IS_EXISTS";


if ([[NSFileManager defaultManager] fileExistsAtPath:checkFilePath]) {

BOOL exists = [[NSUserDefaults standardUserDefaults] boolForKey:checkKey];
if (exists) {
DDLogDebug(@"CHECK:检测到APP已初始化过,获取到值,正常");
}
int i = 0;
while (!exists && i< 20) {
DDLogDebug(@"CHECK:检测到APP已初始化过,但没有获取到USER_DEFAULT中的值,尝试重新获取");
[NSUserDefaults resetStandardUserDefaults];
i++;
exists = [[NSUserDefaults standardUserDefaults] boolForKey:checkKey];
}

//如果还拿不到数据,强制退出,等待用户下一次重启APP
if (!exists) {
exit(0);
}

}

else {
DDLogDebug(@"CHECK:初始化APP");
NSError *error;
[@"WORKPLUS_LOADED" writeToFile:checkFilePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:checkKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}