I am using these methods to save and get data from NSUserDefaults. But NSUserDefaults is being cleared automatically in device after random period of time. I checked the project-
I am not saving any nil or empty string using saveUserName method.
Not using removeObjectForKey, removePersistentDomainForName to reset NSUserDefault.
Code...
+(NSString *) getUserName{
return [[NSUserDefaults standardUserDefaults] objectForKey:kAccUserNameKey];
}
+(void)saveUserName:(NSString *) value {
[[NSUserDefaults standardUserDefaults] setObject:value forKey:kAccUserNameKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
After saving data using saveUserName, I get data properly using getUserName, even after restarting app. But It has been reported that data is being lost sometimes.(getUserName is called from didFinishLaunchingWithOptions and applicationWillEnterForeground) Why NSUserDefault is resetting? any idea??
From documentation
(NSUserDefaults *)standardUserDefaults
Description
Returns the shared defaults object. If the shared defaults object does not exist yet, it is created with a search list containing the names of the following domains, in this order:
NSArgumentDomain
A domain identified by the application’s bundle identifier
NSGlobalDomain
NSRegistrationDomain
Is that means, sometimes shared object does not exist yet and its returning nil? whats the solution?
Did you create NSRegistrationDomain domain for your data dictionary via -registerDefaults: ?
As documentation says:
At launch time, an app should register default values for any
preferences that it expects to be present and valid.
You can do it like this, to make NSUSerDefaults work properly:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSDictionary * defaultsDictionary = #{kAccUserNameKey : #"default name"}
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary];
return YES;
}
In the defaultsDictionary you should specify all data keys you will use in app with their default values.
Related
I need to load user data, but I need to do it looped. (always loading). My code is
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"preferenceName"];
And also, whenever I make an if function, for example
if (t1activity == "active")
{
//code here
}
I get an error saying Expected identifier or '('
Thanks so much! (objective-c)
In the case the value differs only between YES/NO is better to provide a BOOL.
BOOL isUserActive = [[NSUserDefaults standardUserDefaults] boolForKey:#"preferenceName];
and the set method:
[[NSUserDefaults standardUserDefaults]
setBool:YES
forKey:#"preferenceName"];
Then the decision is simpler:
if(isUserActive) {
{
//code here
}
I was curious to know, how often the NSUSerDefaults do update. Here the Apple Docs.
NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. The synchronize method, which is automatically invoked at periodic intervals, keeps the in-memory cache in sync with a user’s defaults database.
I have a simple messaging app, and I'm keeping a dictionary of BOOL:user in the NSUserDefaults which simply represents if something "new" has happened in that conversation. {YES:12343} for example, means there is a new message with user 123432, otherwise NO.
When users interact with each other, I update that dictionary and my view accordingly. And when I leave the app, save the dictionary to the NSUserDefaults. When I come back, I simply load it. Everything works smoothly, expect one thing.
When I tap on a conversation to open it, I set that boolean to NO (because I assume the user has read the message) and save that modified dictionary into the NSUserDefaults again.
Debug shows the dictionary is up to date when saved, but when I tap the "back" button, the view reloads the dictionary from the NSUserDefaults and that dictionary is NOT up to date. So my view is showing the conversation as unread, obviously.
Now the tricky parts comes into play. If I do it again, (sometimes once, sometimes twice), the dictionary will eventually show the conversation as read (because the dictionary will finally be up to date).
This tells me some things :
The dictionary is readable and everything is set "as it should/when it should"
What I get from the NSUserDefaults isn't updated quick enough/at the right time.
What I fail to understand is : when should I save that dictionary and how? I'm loading it in viewWillAppear, and saving it in didSelect. Isn't that the right thing to do ?
Some code :
My didSelect :
pushDict is an NSMutableDictionary object and is never nil at that point
if (pushDict != nil){
[pushDict setObject:[NSNumber numberWithBool:NO] forKey:_friendship.objectId];
[[NSUserDefaults standardUserDefaults]setObject:pushDict forKey:#"pushDict"];
}
And the dictionary loading :
if([[NSUserDefaults standardUserDefaults]dictionaryForKey:#"pushDict"]){
pushDict = [[NSMutableDictionary alloc]initWithDictionary:[[NSUserDefaults standardUserDefaults]dictionaryForKey:#"pushDict"]];
}else{
pushDictFeel = [NSMutableDictionary alloc]init];
}
First of all NSUserDefaults shouldn't be the place where you save information like this. Try to setup a good data model for this. However your error could occure because you are missing this line:
[[NSUserDefaults standardUserDefaults] synchronize];
From your code I can see that you are trying to save a NSMutableDictionary. This will not work since the returned object from the NSUserDefaults is immutable. Have a look at this:
NSMutableDictionary in NSUserDefaults
You need to call synchronize for [NSUserDefaults standardUserDefaults]
if (pushDict != nil){
[pushDict setObject:[NSNumber numberWithBool:NO] forKey:_friendship.objectId];
[[NSUserDefaults standardUserDefaults]setObject:pushDict forKey:#"pushDict"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I need to store a boolean value that would persist only for the app's running time. When the user quit the app (from the background as well) that variable should reset to default. How can I do this?
I tried constants. I keep constants in a separate .h file. In it I declared it like this.
const BOOL hasShownTutorial = NO;
And in the view controller,
if (hasShownTutorial == NO) {
[self showAppTutorial];
hasShownTutorial = YES;
}
I get an error at hasShownTutorial = YES; saying Read-only variable is not assignable.
I also tried going about this using NSUserDefaults. But the thing is the value is stored for good once you set it. Is there a way to clear it up when the app quits?
I'd appreciate your input and suggestions.
Thank you.
Store it in NSUserDefaults under a specific key.
[[NSUserDefaults standardDefaults] setBool:<myBool> forKey:#"myKey"];
Then to retrieve it later.
BOOL b = [[NSUserDefaults standardDefaults] boolForKey:#"myKey"];
If you want to clear the data.
NSString *domain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:domain];
For example, in your AppDelegate's implementation of -applicationWillTerminate:, just clear the data.
- (void)applicationWillTerminate:(UIApplication *)application
{
NSString *domain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:domain];
}
Edit: If the first method of clearing the data does not work, you can use the class method +resetStandardUserDefaults. For example the following would clear the current defaults.
[NSUserDefaults resetStandardUserDefaults];
A third possiblity is to specifically remove a property.
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"myKey"];
You can't change const value since it is a read only memory. Use static keyword instead.
I need a way to initialize a lot of objects only the 1st time my app is installed. So I thought I use this:
-(id) init {
self = [super init];
if(self) {
NSUserDefaults *myUD = [NSUserDefaults standardUserDefaults];
[myUD setObject:#"5" forKey:#"Extra"]; // 5 giving 4 extra diaries
[myUD setObject:#"0" forKey:#"CatchingUp"]; // it's a live diary
[myUD setObject:#"888" forKey:#"SendingSuccess"];
[myUD synchronize];
}
return self;
}
I obviously have many more than theses to initialize but it's just to give you the idea of what I did.
I deleted the app from my phone in order to test, but the init wasn't performed. I put it before ViewDidLoad.
What am I doing wrong please or is there a better way to do it ?
Thank you very much in advance.
If you just want to set up some values at the first time your app runs,
Put this code in app delegate and use this method in didFinishLaunchingWithOptions method,
or you can put this code in your view controller and use this method in viewDidLoad method:)
- (void)setDefaultInfoValue {
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"everLaunched"]) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"everLaunched"];
//put you code here
NSUserDefaults *myUD = [NSUserDefaults standardUserDefaults];
[myUD setObject:#"5" forKey:#"Extra"]; // 5 giving 4 extra diaries
[myUD setObject:#"0" forKey:#"CatchingUp"]; // it's a live diary
[myUD setObject:#"888" forKey:#"SendingSuccess"];
[myUD synchronize];
}
}
At the moment you code will run whenever you create an instance of the class that contains the code - this is likely not what you want (and isn't what you describe).
Instead of setObject:forKey:, you should use registerDefaults: which installs the specified values only if values don't already exist and doesn't save the values to disk. This could be done in the app delegate, or separately in each class that uses different keys from user defaults.
The immediate problem you observe is probably that you aren't creating an instance of the class which contains your code.
I wrote these lines in my code:
CFUUIDRef identifier = CFUUIDCreate(NULL);
NSString *identifierString = (NSString*)CFUUIDCreateString(NULL, identifier);
NSLog(#"%#",identifierString);
[self setValue:identifierString forKey:kParamNameDeviceId];
But these lines are getting called every time when the app launches.
Now my question is, how can the following be achieved?
Create CFUUID.
Store it in some variable in such a way that, when next time my app starts, it should not create a new CFUUID. It should look for the previously created CFUUID and return it.
In short, I want a CFUUID be created ONCE and used throughout the life of the app (till it gets uninstalled).
easiest way is to store it in NSUserDefaults
NSString *identifierString = [[NSUserDefaults standardUserDefaults] objectForKey:#"myID"];
if (!identifierString) {
CFUUIDRef identifier = CFUUIDCreate(NULL);
identifierString = (NSString*)CFUUIDCreateString(NULL, identifier);
[[NSUserDefaults standardUserDefaults] setObject:identifierString forKey:#"myID"];
}
NSLog(#"%#",identifierString);
/* ... */
Create once. Add it in NSUSerDefaults and check whether you have a UUID stored already before creating one. Simple Pseudo code,
NSString *CFUUID = nil;
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"UUID"]) {
//create CFUUDID.
[[NSUserDefaults standardUserDefaults] setObject:CFUUID forKey:#"UUID"];
}
else
{
CFUUID = [[NSUserDefaults standardUserDefaults] objectForKey:#"UUID"];
}
If you are storing identifier on server to keep track of important information regarding unique user than i suggest you store identifierString in "KeyChain" which keeps that identifier even if you application has been deleted by user.
NSUserDefaults keep data until app is deleted. Keychain keeps data even if app is deleted.
I had similar case so this might help if your case is equivalent to mine.