Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/118.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios NSUserDefaults丢失了它的钥匙&;手机重新启动但未解锁时的值_Ios_Background_Nsuserdefaults_Core Location_Reboot - Fatal编程技术网

Ios NSUserDefaults丢失了它的钥匙&;手机重新启动但未解锁时的值

Ios NSUserDefaults丢失了它的钥匙&;手机重新启动但未解锁时的值,ios,background,nsuserdefaults,core-location,reboot,Ios,Background,Nsuserdefaults,Core Location,Reboot,我们的iPhone应用程序目前遇到以下奇怪的问题。正如标题所说,NSUserDefaults在手机重新启动但未解锁时会丢失我们的自定义密钥和值,这是在一个非常特定的场景中发生的 背景: 我们在应用程序中使用NSUserDefaults存储用户数据(例如用户名) 我们的应用程序在后台模式下启用了位置 我们只有在通过空中或试飞进行分发时才会遇到此问题。如果我使用Xcode将.ipa(与空中分发的相同)拖放到手机中,我不会遇到这个问题 情况:用户安装应用程序并登录,用户名成功存储在NSUserDe

我们的iPhone应用程序目前遇到以下奇怪的问题。正如标题所说,
NSUserDefaults
在手机重新启动但未解锁时会丢失我们的自定义密钥和值,这是在一个非常特定的场景中发生的

背景:

  • 我们在应用程序中使用
    NSUserDefaults
    存储用户数据(例如用户名)

  • 我们的应用程序在后台模式下启用了位置

  • 我们只有在通过空中或试飞进行分发时才会遇到此问题。如果我使用Xcode将.ipa(与空中分发的相同)拖放到手机中,我不会遇到这个问题

情况:用户安装应用程序并登录,用户名成功存储在
NSUserDefaults
上。然后,用户关闭设备并重新打开,让手机在解锁屏幕前等待一段时间

问题:如果在此期间触发了重大的位置更改,应用程序将在后台运行,但
NSUserDefaults
为空(只有一些来自苹果的密钥,但没有我们的自定义密钥)。然后,无论您做什么,
NSUserDefaults
都不会恢复此密钥(例如,如果您解锁手机并打开应用程序,您将看到密钥仍然丢失)


任何帮助或想法都将受到真诚的感谢:)

过了一段时间,苹果公司意识到这是一个官方错误。因此,在问题解决之前,我们只剩下不同的解决办法:

  • 如果在解锁手机之前执行操作时需要数据请使用以下选项之一,并设置
    NSPersistentStoreFileProtectionKey=NSFileProtectionNone
    选项:

    • 使用核心数据保存数据。(如果您需要在手机尚未解锁时在后台访问DB,并且其中没有可感知的信息,则可以向选项数组中添加以下选项:
      NSPersistentStoreFileProtectionKey=NSFileProtectionNone
    • 使用钥匙链
    • 使用.plist文件
    • 使用定制文件:(例如:具有特定格式的.txt)
    • 您可能会觉得适合存储数据的任何其他方式
    选择你的;)

  • 如果你不需要或不关心手机前的数据 已解锁您可以使用此方法(感谢@maxf):

    注册到
    applicationProtectedDataDidBecomeAvailable:
    通知并在回调中执行以下代码行
    [NSUserDefaults resetStandardUserDefaults]

    这将使您在手机获得访问受保护数据的权限后立即重新加载
    NSUserDefault
    ,帮助您完全避免此问题


  • 谢谢大家的帮助

    我也遇到了类似的问题。应用程序的背景。使用其他内存密集型应用程序,直到我的应用程序从内存中被丢弃。(如果插入设备并运行构建的xcode,则可以观察此事件。xcode将告诉您“由于内存压力,应用程序已终止”)。从这里开始,如果您的应用程序注册了后台获取事件,它将在某个点唤醒并重新启动,但会进入后台。此时,如果您的设备被锁定,则NSUserDefaults将为空

    在调试这个案例几天后,我意识到不是NSUserDefaults被破坏或禁用,而是由于设备锁定,应用程序无法访问它。如果您手动尝试通过xcode organizer下载应用程序内容,您会注意到存储NS的plist如果设备保持锁定状态,则不存在UserDefaults设置

    好的,如果在设备锁定时将应用程序启动到后台,则无法访问NSUserDefaults。这没什么大不了的,但最糟糕的是,一旦将应用程序启动到后台,它将保留在内存中。此时,如果用户解锁设备并将应用程序启动到前台,您仍然无法访问在NSUserDefaults中有任何内容。这是因为一旦应用程序将NSUserDefaults加载到内存中(该内存为null),它就不知道在设备解锁后重新加载它。在这种情况下,同步不起任何作用。我发现解决问题的方法是调用

    [NSUserDefaults resetStandardUserDefaults]
    应用程序保护数据变得可用的方法中


    希望这对某人有所帮助。此信息可能会让我省下许多小时的痛苦。

    在启用密码的设备上使用重大位置更改时,我们也遇到了此问题。在用户解锁密码之前,应用程序在BG上启动,而UserDefault没有任何内容

    我认为最好在同步发生之前终止应用程序,原因如下:

    • 此错误清除UserDefaults后,不应执行UserDefaults的同步
    • 我们无法严格控制同步调用,因为我们使用了许多第三方库
    • 如果无法加载UserDefaults(即使在用户通过密码锁之前),应用程序也不会有任何好处
    下面是我们(有点奇怪)的解决方法。当检测到情况(app state=BG,UserDefaults被清除,iOS>=7)时,应用程序会立即自杀

    它不应该违反UX标准,因为在后台终止应用程序甚至不会被用户注意到。(而且它发生在用户通过密码验证之前)

    #定义系统版本(大于)或等于(v)([[UIDevice currentDevice]systemVersion]比较:v选项:NSNumericSearch]!=传感器解除搜索)
    +(无效)crashIfUserDefaultsIsInBadState
    {
    如果(系统版本)大于
    
    #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
    
    + (void)crashIfUserDefaultsIsInBadState
    {
        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")
            && [UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
            if ([[NSUserDefaults standardUserDefaults] objectForKey:@"firstBootDate"]) {
                NSLog(@"------- UserDefaults is healthy now.");
            } else {
                NSLog(@"----< WARNING >--- this app will terminate itself now, because UserDefaults is in bad state and not recoverable.");
                exit(0);
            }
        }
        [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"firstBootDate"];
    }
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        [self.class crashIfUserDefaultsIsInBadState]; // need to put this on the FIRST LINE of didFinishLaunchingWithOptions
    
        ....
    }