10

I have a bug submitted by a tester that if he performs an action and then reboots his phone (by pressing the home and Sleep/Wake button down for a few seconds) the app is not persisting state.

I have been able to reproduce this issue. [NSUserDefaults synchronize] is getting called but when I restart the app after the reboot, the value inside NSUserDefaults was not saved.

Does anybody know if synchronize stores to a buffer which is later saved to disk? If so, how do I flush the buffer (I thought synchronize was the same as a flush, but apparently not.)

(edit) In other words:

assert([[NSUserDefaults standardUserDefaults] boolForKey: MY_KEY] == NO);
[[NSUserDefaults standardUserDefaults] setBool: YES forKey: MY_KEY];
[[NSUserDefaults standardUserDefaults] synchronize];

leave the app in the foreground and reboot the device after the above is called, then start the device back up and re-run the app. The assert should fire the second time around, but sometimes it doesn't.

To be very specific... I created a single view application and put the following code in the viewDidLoad

#define MY_KEY @"MY_KEY"

- (void)viewDidLoad
{
    [super viewDidLoad];
    BOOL key = [[NSUserDefaults standardUserDefaults] boolForKey: MY_KEY];
    NSLog(@"[[NSUserDefaults standardUserDefaults] boolForKey: MY_KEY] == %@", key ? @"YES" : @"NO");
    [[NSUserDefaults standardUserDefaults] setBool: !key forKey: MY_KEY];
    [[NSUserDefaults standardUserDefaults] synchronize];
    NSLog(@"reboot now.");
}

Here is the output of three runs of the app:

2013-05-31 12:17:44.127 syncTest[162:907] [[NSUserDefaults standardUserDefaults] boolForKey: MY_KEY] == YES
2013-05-31 12:17:44.133 syncTest[162:907] reboot now.
2013-05-31 12:18:49.771 syncTest[128:907] [[NSUserDefaults standardUserDefaults] boolForKey: MY_KEY] == NO
2013-05-31 12:18:49.778 syncTest[128:907] reboot now.
2013-05-31 12:19:41.388 syncTest[124:907] [[NSUserDefaults standardUserDefaults] boolForKey: MY_KEY] == NO
2013-05-31 12:19:41.397 syncTest[124:907] reboot now.

Note that the output was "YES, NO, NO" but it should have been "YES, NO, YES"

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Daniel T.
  • 32,821
  • 6
  • 50
  • 72
  • Which event are you using to call `[NSUserDefaults synchronize]` – Ric Perrott May 31 '13 at 15:47
  • synchronise should work, might help to see some code. how are you setting and fetching the data? – wattson12 May 31 '13 at 15:48
  • Sounds weird,should not happen.Can you please post some code where you are synchronizing. – Shantanu May 31 '13 at 15:54
  • Where have placed the your call to `[NSUserDefaults synchronize]`? – Mike D May 31 '13 at 15:58
  • I submitted a bug report to Apple: Bug ID# 14034591. – Daniel T. May 31 '13 at 16:46
  • @DanielT. Did you ever get to the bottom of this? I'm seeing a similar problem. – Glen T Nov 01 '13 at 16:18
  • I haven't heard a thing from Apple about it. I worked around it by saving the data in a CoreData object. – Daniel T. Nov 02 '13 at 19:41
  • I submitted the bug 31 May 2013. Apple asked for sample code on 3 Jun 2013, and I submitted the sample code that same day. They haven't replied since. Not even an acknowledgement. – Daniel T. Nov 09 '13 at 18:47
  • I'm seeing the same thing on iOS8. There seems to be a time component. If I wait a few seconds before relaunching, the synchronize seems to save the new value. If I reboot in the first second or two, the value is not updated. – Ben Packard Jan 18 '15 at 14:27

2 Answers2

2

i had gone through the same problem and i identify that i had two reference of [NSUserDefaults standardUserDefaults] object on different classes because nsdefault is a singleton class soo the one called it earlier will have it if u might had already reference of [NSUserDefaults standardUserDefaults] try to finish it from the first reference and let the instance to be free from there and then call the instance at your other class and synchronize hopefully will be done

  • 1
    You will notice that in my sample code, only one class has a reference to NSUserDefaults. So this doesn't answer the question. If it worked for you, I'm happy though. – Daniel T. Feb 27 '14 at 12:59
  • in your sample code it has a one reference but i told u you might have other class that might have the same reference as well soo if u got reference of standarduserdefault object reference set that obj to nil and then use.. and in case if u are not using userdefault somewhere else then have to see what are u exactly doing – Khurram Iqbal Feb 27 '14 at 15:45
  • 1
    Thank you for looking into the issue, but the problem even shows up in the sample code which only has one reference, so obviously the problem has nothing to do with having multiple references. – Daniel T. Mar 01 '14 at 13:31
2

In my case, some values I wrote to the NSUserDefaults did persist and some did not. After lots of searching, I noticed the the key-value pair that did not save had a key that was capipatilized, i.e. TheKey v.s theKey. When I changed my key to a camel-cased key (theKey instead of TheKey), the value did persist thru app quit and re-launch. It seems very weird to me why that would be, but it worked in my case.

ndnguru
  • 91
  • 1
  • 6