NSUserDefaults gets reset - ios

I have an ios app, and recently have been getting some reports from users about their settings getting reset.
The settings are saved using NSUserDefaults.
My question is, can the user defaults get corrupt/reset for some reason?
A few notes about how I use it:
When I start my app, I store default values only if the keys doesn't exist using registerDefaults (this is done to take care of the "first install" scenario).
Most of the aforementioned reports describe the app crashing, and then when it is reopened the settings are reset to default.
My usage of NSUserDefaults is pretty straightforward - saving numbers/strings, reading them sometimes, etc. Nothing too fancy. I don't remove keys.
Some code examples:
For example, I'm saving the data in different places using:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#"FirstLevel" forKey:#"Level"];
[defaults setInteger:100 forKey:#"Score"];
[defaults synchronize];
I read using:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int intValue = [defaults integerForKey:#"Score"];
return intValue;
So, can something cause the user defaults to get reset/corrupt somehow?
More generally, can it be related to the app crashing that was reported, even if the crash is not directly as a result of writing/reading from user defaults?

From what I understand, it is only swiped out when app is deleted. Since your NSUserDefaults' reset issue was preceding by the app crashed, I would start by figure out the crashing issue.

If you install your app in your device the NSUserDefault will be Re initialized again… when ever you test your app in device you will connect your device with Xcode and if you run the program the values will be reset…

Related

Objective-C iOS App: Is there a storage that allows me to save a key-value pair data that will be available between my app restarts?

I'm writing a feature of the language change. First screen of the app I'm writing is about setting the language. When he user presses the button, my app directs user to app settings. I expect user to set some language and show it to them as soon as they go back to my app.
But as soon as I click on some language option, my app xcode console says:
Message from debugger: Terminated due to signal 9
Additionally, as soon as I return to my app, it gets loaded as if I closed and reopened it.
I thought that maybe I can have some code that will set a global variables like "currentLanguage" and "previousLanguage" and if those are different - I will load localisation files for "currentLanguage" and will start downloading localised videos from my server.
System terminate your app when user change language in Settings. So you can use NSUserDefaults for persistent storage and compare this values on app start, to detect if language was changed.
Example:
NSString *currentLanguage = [[NSLocale preferredLanguages] firstObject];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject: currentLanguage forKey:#"previousLanguage"];
NSString *previousLanguage = [userDefaults objectForKey:"previousLanguage"];

How do I determine that my app was just downloaded from AppStore the first time?

This is how it is accomplished in my app:
I keep the data in iCloud.
I need to do some time consuming thing for users who already used my app. But this will also start for completely new users... they just downloaded my app from AppStore for the first time. And this is not expected.
How can I determine that the app is running, but downloaded from AppStore for the first time?
What I could do, but I did not:
put any boolean data in the Keychain, and then check if it exists.
Since you have no non-app end to distinguish users Keychain as you mentioned is your only app persistance option that will survive app uninstalling. Only device Reset to factory settings would remove it.
you can use NSUserDefaults . if appDelegate.m ->didFinishLaunchingWithOptions use this code :
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
if([userDefaults objectForKey:#"first_time"] == nil){
[userDefaults setObject:#"1" forKey:#"first_time"];
//do whatever you need
}
this condition will satisfied only once after installation .

How to detect if app automatically updated in iOS 7

I want to be able to display an alert describing what's new when an app has been updated. What's the best way to do this, especially considering iOS 7 automatically updates apps? Thanks!
You can store the app version in NSUserDefaults. Then if the old app version != current app version you can display your dialog
Version #:
NSString * version = [[NSBundle mainBundle] objectForInfoDictionaryKey: #"CFBundleShortVersionString"];
Set:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:version forKey:#"appVersion"];
Get:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults objectForKey:#"appVersion"];
When the user starts your app, check a version string in user defaults or a file or database.
If you want to do it around the time the app is updated, you might be able to use push notifications in conjunction with the version check. I don't know whether you can get the new app to check the version in the background, though (never used push notifications myself).
Checkout my question I've made some weeks ago (NSUserDefaults behaviour with app update). I think can solve your problem.
The idea is to use NSUserDefaults to store the last version that your device have ever ran, and if a greater version than the one I've got stored in the NSUserDefault object is going to be run, then you do whatever you want to do, in this case displaying an alert describing what's new when the app has been updated.

issue with NSUserDefaults (becomes null)

We are developing an iPhone application. The app is available in the app store. We are using NSUserDefaults to store our usertoken value. But some users reports that the usertoken is became null when the app idle (in background) for long time. But normally the value is getting.
The following is the code for storing usertoken in the NSUserDefaults. We are setting the value to the userToken from the login page and signup pages.
[[NSUserDefaults standardUserDefaults] setObject:userToken forKey:USER_TOEKN];
I have not called synchronize after setting value to NSUserDefaults. Could you please help
You need to call [[NSUserDefaults standardUserDefaults] synchronize]; if your app is going to be backgrounded - my guess is the app idles before the defaults automatically synchronizes. From the documentation:
Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.
As for where to do this, take a look at applicationWillResignActive: and applicationDidEnterBackground: in your Application Delegate.
Try something like this:
NSUserDefaults *udf = [NSUserDefaults standardUserDefaults];
[udf setObject:userToken forKey:USER_TOEKN];
[udf synchronize];
It will store your value permanently.

Persisting NSUserDefaults information between application terminations

In iOS4, when I save NSUserDefaults, the information gets saved. But then, if the application becomes inactive, and I kill the application (by double clicking the home button and then terminating the app), and launch the application again, the NSUserDefaults are not read.
Now, is this the default behaviour of NSUserDefaults that if the app is terminated due to any of the issues, the next launch will not store the information?
The call I am using to persist the info is:-
[[NSUserDefaults standardUserDefaults] registerDefaults:
[NSDictionary dictionaryWithObjectsAndKeys:
"Some date", #"Validity",
nil]];
after you register defaults add this
[[NSUserDefaults standardUserDefaults] synchronize];
until you synchoronize, the standardUserDefaults gives current/correct values as long as the app is alive.
once the app is terminated, since you didn't sync the standardUserDefaults, the app will read the unsynced values on the next launch.
Example: Think of it like a google doc that you are editing.
the AutoSave feature of google document is equivalent to the nsuserdefaults synchornize. If you close the browser before the changes you made to the document has been autosaved, the next time you load it up, you'll see the old content.
The call you mention to persist the user defaults, registerDefaults, does not actually persist anything to disk. What registerDefaults does is initialize the defaults to use for the application if it can't find any on the disk. You should do this on each application launch, typically in the initialize method for the app delegate.
Once your application is running it will typically modify the user defaults. Whenever you want to save these modified defaults to the disk you should call:
[[NSUserDefaults standardUserDefaults] synchronize];
After the defaults have been saved they will be loaded automatically on any subsequent application launches.

Resources