I am creating this application which consists of the users score. When they exit out of the app, there score will be saved. I am doing that through NSUserDefaults which works fine. The problem is that the users score can be manipulated in other views. For example, they can use their score to buy stuff, etc. To do this I am saving the score in NSUserDefaults and then just retrieving that saved data in the next view. The problem is that the data is not being saved for some reason. I have a timer that runs every second that saves the score and I save it using an IBAction when I click the button to go to the next view. Here is what I use to initialize the variable:
score = [[[NSUserDefaults standardUserDefaults] objectForKey:#"score"] longLongValue];
And this is to save it:
[[NSUserDefaults standardUserDefaults] setObject:#(score) forKey:#"score"];
I am using a long long variable which is why I have it as an object as opposed to integer. I do not understand why the values are getting changed as I change views. Anytime I manipulate the score value, I save it. At the top of each view I am declaring it. I realize that other people have posted similar questions, and I have viewed them all. Those responses did not solve my problem which is why I asked on here. Synchronize
[[NSUserDefaults standardUserDefaults] synchronize];
has not worked for me either.
Only thing you are missing is, synchronize you are not telling NSUserDefault to write data on disc.
// *** Get your score value ***
score = [[[NSUserDefaults standardUserDefaults] objectForKey:#"score"] longLongValue];
// *** manipulate it if needed ***
score+=100;
// *** save it back to `NSUserDefaults` ***
[[NSUserDefaults standardUserDefaults] setObject:#(score) forKey:#"score"];
// *** Synchronize your updates to `NSUserDefaults` by calling it, it immediately write data to disc ***
[[NSUserDefaults standardUserDefaults] synchronize];
For more details about NSUserDefaults read Apple Documentation
Use this. This will save the value
[[NSUserDefaults standardUserDefaults] setObject:#(score) forKey:#"score"];
[[NSUserDefaults standardUserDefaults] synchronize];
Related
I am doing a project in objective-c and I have to store some values in userDefaults. I am already did the same thing in the same project. It was working fine but now I am trying to add some values in userDefaults it showing error while fetch any data from userDefaults. I am adding the datas as,
NSString * totalBitValue = [NSString stringWithFormat:#"%.6f Bit",
totalValue /
[[[NSUserDefaults standardUserDefaults] objectForKey:#"Bit"] floatValue]];
[[NSUserDefaults standardUserDefaults]setObject:totalBitValue forKey:#"totalBTCValue"];
[[NSUserDefaults standardUserDefaults]setFloat:totalUSDValue forKey:#"totalUsedValue"];
[[NSUserDefaults standardUserDefaults] synchronize];
and the error as ,
error: Trying to put the stack in unreadable memory at: 0x7ffeeafe2af0
I got the error in the following line,
if( [[NSUserDefaults standardUserDefaults] objectForKey:#"CoinValue"] != nil) {
[[self ValueLabel] setText: [NSString stringWithFormat:#"%#", [[NSUserDefaults standardUserDefaults] objectForKey:#"CoinValue"] ]];
}
Anyone can help me.Thanks in advance
The reason for your issue is because your code gets recursion.
As I understand, you used NSNotificationCenter to observer key NSUserDefaultsDidChangeNotification. So whenever NSUserDefaults is updated, it will trigger defaultsChanged method. But inside it, you continue to change NSUserDefaults, set new value for totalBTCValue and totalUSDValue (as I guess) which makes defaultsChanged be called again and leads to recursion.
To fix the issue, you shouldn't update NSUserDefaults inside defaultsChanged method
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 am really new to iOS programming and forgive me if I sound a bit ignorant but, whenever I try to save a high score within my app using NSUserDefaults I always lose it after the app is shut down.
This is in my viewDidLoad method:
[[NSUserDefaults standardUserDefaults]setInteger:egtTopScr forKey:#"egtSectopScore"];
[[NSUserDefaults standardUserDefaults] synchronize];
[prefs setInteger:egtTopScr forKey:#"egtSectopScore"];
This is what happens to the top score when the game ends:
if(scoreCounter > egtTopScr) {
egtTopScr = scoreCounter;
}
topScore.text = [NSString stringWithFormat:#"Best: %i", egtTopScr];
After the app launches you have to load the integer you saved.
NSInteger score = [[NSUserDefaults standardUserDefaults] integerForKey:#"egtSectopScore"]
// do some stuff with score
I am new to iOS development and have the following problem.
EXPLANATION:
I have an app which consists of several mini games. Each mini game is available through in app purchase. However the mini game availability is saved in a BOOL variable like this:
_miniGamesArray = [[NSMutableArray alloc] init];
NSMutableDictionary *mutDictMg0 = [NSMutableDictionary dictionaryWithCapacity:3];
[mutDictMg0 setValue:[self.gameAvailabilityMutableArray objectAtIndex:0] forKey:#"GameAvailable"];
[_miniGamesArray addObject:mutDictMg0];
PROBLEM:
Each time I start the app the game availability is checked from the self.gameAvailabilityMutableArray which is set to:
- (NSMutableArray *)gameAvailabilityMutableArray
{
if (!_gameAvailabilityMutableArray)
{
//[_gameAvailabilityMutableArray addObjectsFromArray:#[#1,#0,#0,#0 ,#0,#0,#0,#0]];
_gameAvailabilityMutableArray = [[NSMutableArray alloc] initWithArray:#[#1,#1,#1,#1 ,#1,#1,#1,#1]];
}
return _gameAvailabilityMutableArray;
}
When the customer buys a mini game I want the array to be set to (example):
#[#1,#1,#0,#0 ,#0,#0,#0,#0]]
TRIED SOLUTIONS:
I tried to implement the array by calling the iTunes server and writing the data. However, the time to recieve the request is greater then the app loading time. The second problem arrises if there is no internet connection, then the app crashes.
I also tried using .plist files. I don't know why but writing to the plist file doesn't change it's contest all the time! Some times it works , sometimes it doesn't... Sometimes the app loads the values correctly sometimes it mixes them with the last values.
QUESTION:
Is there a way to store permanent app data which is being checked when the app loads beside plists?
Thank you for your time.
save your data in NSUserDefaults.then use below conditions for app start first time or handle another conditions.
BOOL iSFirstTime = [[NSUserDefaults standardUserDefaults] boolForKey:#"AppStartFirstTime"];
if (!iSFirstTime) {
NSLog(#"Application start first time");
[[NSUserDefaults standardUserDefaults] setValue:#"ImgDownloaded" forKey:#"ProductIDDef"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"AppStartFirstTime"];
}else{
// NSLog(#"we are here");
if ([[[NSUserDefaults standardUserDefaults] valueForKey:#"ProductIDDef"] isEqualToString:#"ImgDownloaded"]) {
NSLog(#"All transaction and Image Downloading has been perform successfully");
}else{
//If any network problem or any thing else then handle here.
}
}
}
You can save the data in NSUserDefaults using the following code:
[[NSUserDefaults standardUserDefaults] setObject:_gameAvailabilityMutableArray forKey:#"gameArray"];
[[NSUserDefaults standardUserDefaults] synchronise];
and you can retrieve the array using
_gameAvailabilityMutableArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"gameArray"];
I want to display a help message on a view controller when the app is installed and opened for the very first time ONLY.
Is there a method I can use to do this?
You can display the help message once, and then store a boolean value in NSUserDefaults to indicate that it should not be shown again:
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
BOOL appHasBeenLaunchedBefore = [userDefaults boolForKey:#"HasBeenLaunched"];
if (!appHasBeenLaunchedBefore)
{
[self showHelpMessage];
}
[userDefaults setBool:YES forKey:"HasBeenLaunched"];
Use Grand Central Dispatch's dispatch_once() and check some persistent storage.
static dispatch_once_t pred;
dispatch_once(&pred,^{
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
BOOL hasLaunched = [userDefaults boolForKey:kAppHasLaunched];
if (!hasLaunched) {
[self showFirstLaunchMessage];
[userDefaults setBool:YES forKey:kAppHasLaunched];
}
});
This is the easiest way to ensure code only gets run once in your app per launch (in this case the block will only be executed once). More information about this is in the Grand Central Dispatch Reference. In this block you simply need to check some persistent storage, such as your preferences, to see if your app has ever launched before and display a message as appropriate.
Use a key in the user defaults. For example:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
BOOL launchedBefore = [userDefaults boolForKey:#"hasRunBefore"];
if(!hasRunBefore)
{
NSLog(#"this is my first run");
[userDefaults setBool:YES forKey:#"hasRunBefore"];
}
The user defaults are backed up by iTunes, so it'll normally be the user's first launch rather than the first launch per device.
EDIT: this is explicitly the same answer as e.James gave before me. The 'other answers have been posted' bar failed to appear. I'll leave it up for the example code but don't deserve credit fir a first answer.