18 Replies
      Latest reply on Mar 3, 2018 11:56 AM by Beast
      ericcj Level 1 Level 1 (0 points)

        There have been many threads and bugs about this, but it's happening to me again in ios 9.  I have an app that launches in the background in response to NSURLSession tasks and content-available pushes.  Reproducibly, if I reboot my phone and wait for a background launch of my app to happen, then when I open the app I find that [[NSUserDefaults standardUserDefaults] dictionaryRepresentation] contains all the system values, e.g. AppleITunesStoreItemKinds, etc. but does not contain any of the values I have set.  If I force-quit and relaunch the app all of my values come back.  Is there any way to avoid it caching the "empty" standardUserDefaults from before the phone is unlocked, or at least to determine when they are messed up and fix them without having to force-quit the app?

         

        Thanks,

        eric

         

        previous discussions:

        https://devforums.apple.com/thread/212999

        http://www.openradar.me/16761393

        • Re: NSUserDefaults values lost on background launch
          eskimo Apple Staff Apple Staff (11,625 points)

          The problem here is that NSUserDefaults is ultimately backed by a file in your app’s container and your app’s container is subject to data protection.  If you do nothing special then, on iOS 7 and later, your container uses NSFileProtectionCompleteUntilFirstUserAuthentication, a value that’s inherited by the NSUserDefaults backing store, and so you can’t access it prior to first unlock.

          IMO the best way around this is to avoid NSUserDefaults for stuff that you rely on in code paths that can execute in the background.  Instead store those settings in your own preferences file, one whose data protection you can explicitly manage (in this case that means ‘set to NSFileProtectionNone’).

          There are two problems with NSUserDefaults in a data protection context:

          • Its a fully abstract API: the presence and location of its backing store is not considered part of that API, so you can’t explicitly manage its data protection.

            Note On recent versions of OS X NSUserDefaults is managed by a daemon and folks who try to manipulate its backing store directly have run into problems.  It’s easy to imagine the same sort of thing coming to iOS at some point.

          • Even if changing the data protection were possible, NSUserDefaults has no mechanism to classify data based on the context in which you’re using it; it’s an ‘all or nothing’ API.  In your case you don’t want to remove protection from all of your user defaults, just those that you need to access in the background before first unlock.

          Finally, if any of this data is truly sensitive, you should put it in the keychain.  Notably, the keychain does have the ability to set data protection on an item-by-item basis.

          Share and Enjoy

          Quinn "The Eskimo!"
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: NSUserDefaults values lost on background launch
              Wellington Level 1 Level 1 (0 points)

              Quinn,

               

              We just run into a similar issue whilst adding background fetch to our app. Until now, our default Data Protection (as specified in the App ID) has been "Complete". I was wondering if changing this to "until first unlock" would have any affect on existing installs of the app as far as NSUserDefaults is concerned once the user updates to the newer version of the app, or will the existing backing store remain at "Complete" for ever?

                • Re: NSUserDefaults values lost on background launch
                  eskimo Apple Staff Apple Staff (11,625 points)

                  I was wondering if changing this to "until first unlock" would have any affect on existing installs of the app as far as NSUserDefaults is concerned once the user updates to the newer version of the app, or will the existing backing store remain at "Complete" for ever?

                  AFAIK changing the default file protection setting for the app does not change the settings of existing containers that are updated to the new version.

                  Share and Enjoy

                  Quinn "The Eskimo!"
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                    • Re: NSUserDefaults values lost on background launch
                      Wellington Level 1 Level 1 (0 points)

                      Hmm, So the NSUserDefaults of existing users are going to be stuck at "Complete" forever.

                       

                      Would using [NSUserDefault resetStandardUserDefaults] cause the defaults file to be recreated with the new protection setting? If so, I can always copy all the defaults I care about, reset the defaults and then re-add them.

                       

                      I suspect the answer is no though.

                        • Re: NSUserDefaults values lost on background launch
                          dgatwood Level 1 Level 1 (10 points)

                          The file is in your app's container directory, so you should (in theory) be able to modify its data protection yourself.  Use NSFilemanager to set its NSFileProtectionKey attribute.  Of course, as Quinn said, there's the potential for all sorts of fun if iOS ever implements the joy that is OS X's cfprefsd (which I find myself killing at least once a week after hand-modifying some random preferences file), but at least doing so would give you a way to fix the problem for existing users for now.

                           

                          Alternatively, you could move that data out of the preferences file, and then use the isProtectedDataAvailable method on UIApplication to determine whether or not to read your app's preferences.

                    • Re: NSUserDefaults values lost on background launch
                      ericcj Level 1 Level 1 (0 points)

                      Thanks for the attention Quinn.  The problem isn't that I need access to NSUserDefaults before the first unlock, it's that if my app is launched before the first unlock then after I do actually unlock the phone the NSUserDefaults are stuck cached in the poisoned, empty state as if it had never been unlocked.  I guess I should file a radar?  It seems like there's been several of them over the years so I want to make sure there's not something else I'm supposed to be doing:  http://www.openradar.me/16761393

                        • Re: NSUserDefaults values lost on background launch
                          AmitS Level 1 Level 1 (0 points)

                          Dear Quinn

                          I'm experiencing the very same problem like Eric,

                          This is the scenario I experience:

                          1. Phone battery is off - it is shut down

                          2. Connect the phone to power

                          3. Unlock the phone and lock again.

                          4. After a while - a beacon detection event makes my App launch in the background.

                           

                          Like Eric mentioned - in this Launch, I get NULL for my saved custom NSUserDefaults values that I need for the launch.

                          If I will kill the App and reopen it - values will be read correctly from NSUserDefaults.

                           

                          It is for sure nothing to do with first unlock after reboot, because I unlocked it, locked it again and only after that - App launched in background not being able to get the good NSUserDefaults values.

                           

                          I hear from you that it will not happen with file righ?

                          Eric - how did you solve it?

                           

                          Thanks

                        • Re: NSUserDefaults values lost on background launch
                          mishag Level 1 Level 1 (0 points)

                          Hi Quinn,

                           

                          A while ago you said that you thought iOS apps are never launched before first unlock in the following thread-

                           

                          https://devforums.apple.com/message/956199#956199

                           

                          "IIRC we don't auto launch apps until after the first unlock so I don't think this will be an issue in practice."

                           

                          It seems per your comment above that now iOS apps can be launched before first unlock. Can you describe a circumstance in which an app will be launched before first unlock in iOS 9?

                           

                          I have tested a number of background launch scenarios - nsurlsession background download, voip, background fetch, significant location change, remote push. None of them appear to launch the app before first unlock.

                           

                          Your help is appreciated.

                           

                          Thanks,

                          Misha

                            • Re: NSUserDefaults values lost on background launch
                              eskimo Apple Staff Apple Staff (11,625 points)

                              A while ago you said that you thought iOS apps are never launched before first unlock in the following thread-

                              Yeah, the ‘auto launch before first unlock’ story is a complex one, where the specifics have changed over time, and I don’t have all the details on it.  AFAIK it is currently (iOS 9) possible for apps to be auto launched before unlock under these circumstances:

                              • VoIP

                              • region monitoring

                              However, I’m not the expert on this.  If you need definitive answers, please open a DTS tech support incident and one of my colleagues can help you out.

                              Regardless, my advice from my earlier (Aug 27, 2015) post still stands: NSUserDefaults is not the right API to use if you need control over the accessibility of your data in the background.

                              Share and Enjoy

                              Quinn "The Eskimo!"
                              Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                              let myEmail = "eskimo" + "1" + "@apple.com"

                              DTS will close for the winter holidays at the end of business on Wed, 23 Dec 2015 and re-open on Mon, 4 Jan 2016.

                                • Re: NSUserDefaults values lost on background launch
                                  mishag Level 1 Level 1 (0 points)

                                  Ok thanks very much Quinn.

                                   

                                  Misha

                                    • Re: NSUserDefaults values lost on background launch
                                      SFCris Level 1 Level 1 (0 points)

                                      What error will be received if an App is blocked access to NSUserDefaults because the data is subject to data protection?

                                      What I see is result values are 0 which, unfortunately can be a valid value.

                                       

                                      Is there an API call to determine if NSUserDefaults are accessible?

                                        • Re: NSUserDefaults values lost on background launch
                                          eskimo Apple Staff Apple Staff (11,625 points)

                                          NSUserDefaults does not have any way to communicate this error back to you.  For example, for the central NSUserDefaults method, -objectForKey:, a result of nil means that the value is unavailable, but there’s no way to distinguish between this key is not present and this value can’t be fetched because the user defaults are offline.

                                          Which brings me back to the advice from my first response on this thread: if your app accesses critical data while in the background, store that in your own file or, if the data is sensitive, in the keychain.  That gives you explicit control over the data protection class used for your data.

                                          Share and Enjoy

                                          Quinn “The Eskimo!”
                                          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                          let myEmail = "eskimo" + "1" + "@apple.com"

                                • Re: NSUserDefaults values lost on background launch
                                  jordanMN Level 1 Level 1 (0 points)

                                  I am having a similar problem with iOS 10 and 11.  I don't need to access NSUserDefaults from the background, but after a few months of testing background execution, I have found that very rarely I am unable to access NSUserDefaults from applicationDidBecomeActive just after applicationProtectedDataDidBecomeAvailable was called.  It seems to be a timing issue, as though NSUserDefaults is occasionally not yet unencrypted and available by the time applicationDidBecomeActive has started executing.

                                    • Re: NSUserDefaults values lost on background launch
                                      Vocera Level 1 Level 1 (0 points)

                                      I have encountered this issue as well, I am able to reproduce it on iOS 11.1.1.

                                       

                                      - (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application
                                      {
                                          VMPLogVerbose(@"applicationProtectedDataDidBecomeAvailable");
                                          [NSUserDefaults resetStandardUserDefaults];/
                                          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                                              [NSUserDefaults resetStandardUserDefaults];/
                                              [self launchApplication:nil];
                                          });
                                      }
                                      

                                      Even if Calling resetStandardUserDefaults multiple times, it does not help. it sounds iOS issue.

                                        • Re: NSUserDefaults values lost on background launch
                                          jordanMN Level 1 Level 1 (0 points)

                                          Did you ever find a way to deal with this problem?  Does simply waiting get you access to NSUserDefaults?

                                           

                                          We have seen in our testing that making the app inactive (i.e., hit the home button) and waiting (the one time this happened, the device was locked and then unlocked), then NSUserDefaults becomes available again after the app restarted in the background.  This makes me think that the problem is either a timing issue (we just need to wait a little longer...) or the decryption process on NSUserDefaults just failed, and we need to go through the process again to get to that data.  If it is a timing problem, then I can build a wait into my launch, like you did, and deal with the problem that way.  But if the problem won't go away during the process of foregrounding, then I have no recourse but to make my app crash, so the user can restart it.  I really don't want to make my app crash on purpose!!!

                                          • Re: NSUserDefaults values lost on background launch
                                            enrom Level 1 Level 1 (0 points)

                                            I have the same problem on iOS11. After having rebooted iOS device and launch the app all data in NSUserDefaults are not available.

                                            The problem doesn't raise if I remove the request of passcode to access to iOS device. Until now I didn't find any solution.

                                        • Re: NSUserDefaults values lost on background launch
                                          fsaf33 Level 1 Level 1 (0 points)

                                          I also running into this issue. We have a voip app. App wakes up at background before first unlock. And NSUserDefaults is stay bad states until phone unlock and app restart.

                                           

                                          I am trying to find a replacement for NSUserDefaults. I wonder if core data is a good choice, I haven't try core data yet.

                                           

                                          Does anyone has a solution yet for NSUserDefaults replacement?