17

NOTE: I have seen many other posts on Stack Overflow about NSUserDefaults being renamed to UserDefaults in Swift or not working on simulator until a restart. This is not a duplicate by anyway. Many of the questions SO is tagging against is from 4 years ago. My question is specific to iOS 10 from this year as this has always worked in older versions. I have mentioned in my question already that my question is not a duplicate of those questions as those were simulator bugs in swift and my issue is on device objective C bug. Please read the questions before marking as duplicate

My issue is different as I am able to reproduce this on objective C and on physical device itself.

I created a brand new project from scratch for this test. I placed this code in the viewDidLoad of a view controller:

if (![[NSUserDefaults standardUserDefaults] valueForKey:@"checkIfInitialized"]){
    NSLog(@"setting checkIfInitialized as not exist");
    [[NSUserDefaults standardUserDefaults] setValue:@"test" forKey:@"checkIfInitialized"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    self.view.backgroundColor=[UIColor redColor];
    self.mylabel.text=@"NSUserDefaults was NOT there, try running again";
} else {
    NSLog(@"checkIfInitialized exists already");
    self.view.backgroundColor=[UIColor blueColor];
    self.mylabel.text=@"NSUserDefaults was already there this time, try running again";
}

Now if I run the app about 10 times, few times it finds the checkIfInitialized and sometimes it doesn't. No exact number on how many times it fails as it might work 3 times then fail next 2 times then work 4 times and fail once and so on.

Now something I have noticed (not 100% sure though) that the issue only seems to happen when I am testing connected via Xcode. If I run by launching the app by clicking the app icon on device without Xcode, then it seems to work fine but I can't be 100% sure.

I noticed this error occur sometimes:

[User Defaults] Failed to write value for key checkIfInitialized in CFPrefsPlistSource<0x1700f7200> (Domain: com.xxxx.appname, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null)): Path not accessible, switching to read-only

I have this very simple project on my dropbox if you want to test it out. I would suggest testing about 10-15 times to reproduce this issue.

https://www.dropbox.com/s/j7vbgl6e15s57ix/nsuserdefaultbug.zip?dl=0

This works completely fine on iOS 9 so definitely something to do with iOS 10.

EDIT Bug logged: 28287988

Response from apple DTS team:

First off, you should first determine whether standardUserDefaults or valueForKey is failing. My guess is that “standardUserDefaults” is returning NULL and, if that’s the case, then that’s something you should be guarding against generally. Notably, standardUserDefaults will return NULL if the preference file is encrypted in the environment the app is currently running in (for example, preferences is set to “NSFileProtectionComplete” and the app is running in the background). That shouldn’t be an issue for standard foreground-only apps, but it’s something to be aware of anyway.

It’s very likely that Xcode is actually inducing the problem here. Xcode vastly complicates the app launching environment in a way that’s VERY different than a standard app launch. My guess is that this is basically being triggered by Xcode’s timing inducing an an expected situation during the app launch, but if you want a more formal test of that try setting a single breakpoint in applicationDidFinishLaunching and continuing in the debugger as soon as you hit it. My guess is just adding that disrupts the timing enough to stop the problem from happening. Sort of. It’s iOS 10 only in the sense that iOS 9 will never print that log message, but that’s because the log message was added in iOS 10. The code itself is similar enough to iOS 9.3 that I suspect exactly the same behavior is (at least in theory) possible in iOS 9.

arlomedia
  • 8,534
  • 5
  • 60
  • 108
  • @Hamish this is not a duplicate by anyway. that question is from 4 years ago. My question is specific to iOS 10 from this year as this has always worked in older versions. – sudoExclaimationExclaimation Sep 12 '16 at 19:45
  • 1
    Possible duplicate of [iOS 10, NSUserDefaults Does Not Work](http://stackoverflow.com/questions/37840288/ios-10-nsuserdefaults-does-not-work) – JAL Sep 12 '16 at 19:50
  • @JAL I have mentioned in my question already that my question is not a duplicate of those questions as those were simulator bugs in swift and my issue is on device objective C bug. Please read the questions before marking as duplicate – sudoExclaimationExclaimation Sep 12 '16 at 19:54
  • 1
    The question is a duplicate. Just because the answers on the linked question did not help you does not mean that your question has not been asked before. I see you have edited your question to show why you believe this is not a dupe. Hopefully someone comes along and can solve your problem. – JAL Sep 12 '16 at 19:56
  • @JAL that makes no sense. If a question did not help me because it's not the same question, then that means that it has not been asked before. I clearly mentioned in my question it's not specific to swift syntax changes or simulator problems which those questions are about – sudoExclaimationExclaimation Sep 12 '16 at 19:59
  • 1
    You clearly did not read the linked question, as it has nothing to do with Swift. – JAL Sep 12 '16 at 19:59
  • @JAL you are right about the swift thing. the swift syntax change i was referring to the other link Hamish had linked before (seems like he deleted his comment now). Your link does talk about the simulator specific bug which is not related to my question either. – sudoExclaimationExclaimation Sep 12 '16 at 20:03
  • 1
    Definitely not a duplicate of the other questions, which referred either to a Swift language change or to an incompatibility between iOS simulators. This is reproducible on devices and in the simulator and is indeed intermittent. – nugae Sep 13 '16 at 21:29
  • It **does** also happen when clicking on the app icon on the device, without Xcode being involved. – nugae Sep 13 '16 at 21:30
  • @nugae it does? for me i wasn't able to reproduce without xcode but maybe i didn't try enough number of times. did you use my project? – sudoExclaimationExclaimation Sep 13 '16 at 21:31
  • FYI I'm seeing similar issues with our production app on iOS 10 – Dan Marinescu Sep 20 '16 at 08:48
  • @DanMarinescu I added apple DTS team's response to my question if you are interested! – sudoExclaimationExclaimation Sep 20 '16 at 18:29
  • 1
    thanks @PranoyC, that's useful – Dan Marinescu Sep 21 '16 at 07:36
  • @DanMarinescu We're seeing this issue in the field too. iOS 10 users (only) are reporting the login screen re-appearing, which is controlled by a boolean NSUserDefault that is only read from or is written to with YES (never NO). I'm thinking it may be related to Bitcode, since this code has been in our app for 3 years and the only major difference is we enabled Bitcode. – jasonjwwilliams Dec 22 '16 at 20:25
  • @jasonjwwilliams you can try adding a 1 second delay before you check the `NSUserDefaults` after launch of app. Not perfect solution but can be something worth it. – sudoExclaimationExclaimation Dec 22 '16 at 22:21
  • @PranoyC Yeah that makes me uncomfortable. It would be nice if Apple would admit this was a problem now. It really makes NSUserDefaults unusable if its going to be unreliable. – jasonjwwilliams Jan 04 '17 at 00:58
  • I just started to find this problem myself. Using XCode 8.3.3, IOS 10 Simulator. The NSUserDefaults don't load properly (I output them all when the app starts) all the time. Maybe 3/10 times it fails. When this happens I stop the app in the simulator, wait, and restart. It usually works after that. So it does seem to be a timing issue but hard to tell. Very annoying and scares me a lot to think that this might happen on an actual device. Also I proved that NSUserDefaults standardUserDefaults is NOT returning nil - I can see other defaults such as NSLanguages, etc. – Larry Jul 20 '17 at 17:44
  • I've been seeing this problem for a month now. App is released through TestFlight, and launching by hand. Data Protection is enabled. @jasonjwwilliams Any solution other than adding a 1 second delay? – Kevin Packard Sep 16 '18 at 18:29

2 Answers2

9

Yes, this is definitely a reproducible bug.

  • It happens with the GM release of Xcode 8 and iOS 10.
  • It is not the linked question referring to Swift.
  • It is not the linked question referring to beta versions of the Simulator.

The bug happens on devices and on the Simulator. It is intermittent: saving will work six times and then fail. Unlike you, I did not get the "failed to write key" message.

The bug also occurs when operating directly on the device without Xcode. This is in fact how I discovered it.

You should report a bug to Apple, especially since you have a short program that will reproduce it. I will do the same.

One key difference: In my case the failure is in writing the default. The previously written value remains in NSUserDefaults. Sometimes one key is successfully written while another is unchanged.

nugae
  • 499
  • 2
  • 5
  • thanks for the update! I just logged a DTS with Apple couple minutes ago as now I know that I am not the only one facing the issue. If they think this should be a bug too, then this will be a pretty major bug and cause many issues in the apps. – sudoExclaimationExclaimation Sep 13 '16 at 21:44
  • 1
    I just reported a bug 28287988 and logged a DTS too. Will update what I find. – sudoExclaimationExclaimation Sep 13 '16 at 21:51
  • Bug 28289469 here. – nugae Sep 13 '16 at 23:00
  • I added apple DTS team's response to my question if you are interested! – sudoExclaimationExclaimation Sep 20 '16 at 18:29
  • You saved what is left of my hair!!! I've been pulling it out for the last few days trying to figure out wtf is going on. I began to suspect some kind of iOS bug because things are happening that should NOT be possible. I have an App in the field and am getting reamed by users for a problem caused by the intermittent failure to write changes to NSUserDefaults during initialize of AppDelegate to support changes to an existing feature. I am on the 3rd attempt and still getting smacked around by my users.... at least now I know why and have a better chance of putting in place a workaround fix. – Cliff Ribaudo Dec 24 '16 at 15:01
0

A similarly very intelligent DTS response from my own support request. Basically, killing using Xcode is more murderous than anything that would naturally happen on the device (even the double-Home-click-and-upswipe method) and since everything is abruptly crashed when Xcode halts it, the lazy writing of NSUserDefaults can fail, or be only half completed.

And indeed, pure on-device testing of the app, without Xcode involved, shows that everything does get correctly written to NSUserDefaults when the app is terminated.

I have closed my own bug report.

nugae
  • 499
  • 2
  • 5