为什么在扁平电池IOS7之后无法读取NSUserDefaults

前端之家收集整理的这篇文章主要介绍了为什么在扁平电池IOS7之后无法读取NSUserDefaults前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用NSUserDefaults存储应用程序EULA和PP是否已被接受(除其他外)这一般工作正常.我可以开始,退出然后返回到应用程序,它读取值很好.我可以杀死应用程序并重新启动 – 读取默认值.我可以重新启动手机,然后重新启动应用程序,它会读取默认设置.

但是当手机从平板电池重新启动时,我打开应用程序并提示再次接受我的EULA PP.这只发生在IOS7上的iPhone5上.我在IOS6上有一个3GS,它没有表现出相同的行为.

我怀疑它可能是解决here问题的类似问题,但这指的是钥匙串中的许可问题.相同的权限问题是否适用于NSUserDefaults?

有没有人在使用NSUserDefaults的IOS7上遇到过类似的问题?

解决方法

所以经过实验和谷歌搜索我得出的结论如下:

显着的更新更改,实际上任何在锁定屏幕后启动应用程序的进程都是此处的问题. [NSUserDefaults defaultUser]加载的文件.plist受到保护(NSFileProtectionCompleteUntilFirstUserAuthentication),因此在应用程序启动后第一次解锁后才能访问它.因此,如果进程在后台启动您的应用程序并且您的应用程序尝试访问defaultUser用户默认值,则无法加载该文件,因此会为您提供一组新的用户默认值.

在我的案例中发生的事情是,应用程序然后进入等待EULA和PP被接受的状态,因为它从默认值(无法读取)中读取它们尚未被接受.解锁手机并重新打开应用程序 – 请注意已经“启动” – 有一些进程写入NSUserDefaults,一些在我的应用程序中,一些在我的应用程序使用的库中.在大多数情况下,我在默认情况下调用同步,因此爆破了无法读取的旧默认值.我想这可能是很多人的情况.

有几种不同的解决方案.

首先,我编写了一个等同于NSUserDefaults的类,它包装了一个NSMutableDictionary,并将字典保存到库/应用程序支持中的.plist.我将文件上的保护更改为NSFileProtectionNone.请注意,如果将敏感信息存储在此文件中,则不建议这样做.另请注意,每次编写文件时都必须设置文件的权限.就像是:

NSError *error;   
BOOL saved = [defaultsDic writeToURL:defaultsFileUrl atomically:YES];
[[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObject:NSFileProtectionNone forKey:NSFileProtectionKey]ofItemAtPath:[defaultsFileUrl path] error:&error];

这种方法工作正常,但事实证明我有另一个问题,我正在从钥匙串读取和写入数据.请参阅上面我的问题中的链接,它是同样的问题.在应用程序启动后第一次解锁之前,钥匙串值具有相同的保护.我不想删除对钥匙串的保护,我实际上也不太习惯从我的自定义用户默认设置中删除保护.

所以下一个解决方案是实际解决问题.如果应用程序在锁定屏幕后面启动,请不要尝试访问受保护的数据!这意味着我必须检测到应用程序是在锁定屏幕后面启动的,然后等到应用程序解锁后再继续读取我的用户默认值和钥匙串值.

第一个要求是检查应用程序启动是否有受保护的数据,因此可能在applicationDidLaunch或其他合适的地方.

[[UIApplication sharedApplication]isProtectedDataAvailable]

如果启动应用程序时不是这样,那么您就在锁定屏幕后面.您应该暂停此操作并避免访问NSUserDefaults或Keychain(或任何受保护的文件!)的任何操作.然后,您需要等待受保护数据可用的信号.当用户解锁锁定屏幕时,appDelegate会收到以下信息:

-(void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application

收到后,您可以继续执行您的申请.

在我的情况下,我控制单例类中的所有内容.创建该类时(仅在应用程序启动时发生)我检查受保护数据是否可用,并订阅NSNotificationCenter以获取相同的通知

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(applicationProtectedDataDidBecomeAvailable) name:UIApplicationProtectedDataDidBecomeAvailable object:nil];

因此,使用第二种方法,问题得以解决,数据仍然受到保护,每个人都很高兴.

猜你在找的iOS相关文章