Creating a plist to access a variable and rewriting it - objective-c

Is it possible to create a plist to hold one variable integer called CurrentQuestion which can be altered.
This variables value will be constantly changed by various different classes which can access the new value of the currentQuestion.
I seem to be having a problem transferring the value of variables using the prepareForSegue function and think this option may be the best option.

You should use NSUserDefaults to store this.
// setting logic
[[NSUserDefaults standardUserDefaults] setInteger:1 forKey:#"CurrentQuestion"];
[[NSUserDefaults standardUserDefaults] synchronize];
// retrieval logic
NSInteger currentQuestion = [[NSUserDefaults standardUserDefaults] integerForKey:#"CurrentQuestion"];
It will persist between application launches as well so take that into consideration.

Related

Problems in getting an array from NSUserDefaults

I am making a game using cocos2d-iphone and would like to make a screen with best previous scores. I have two scenes. In the MainScene I made a global variable for storing a score, that is obviously changing during the game; one mutable array and one simple array that will be a duplicate for the mutable one:
NSInteger _scoreValue;
NSMutableArray *_scoresMutable;
NSArray *_scores;
In the same class, when game ends, I add new score to the mutable array, make a static duplicate and save it in NSUserDefaults:
[_scoresMutable addObject:#(_scoreValue)];
_scores=[NSArray arrayWithArray:_scoresMutable];
[[NSUserDefaults standardUserDefaults] setObject:_scores forKey:#"gameScores"];
Then, in other class of scene with scores called bestscores(I don't know how is better, but it was easier for me to make just a new scene, because I am using SpriteBuilder) I import MainScene.h just in case and make a label.
At the moment I am trying to get all scores from NSUserDefaults, to sort it and to show second biggest value. But it always shows 0 (label is empty by default). So, how to make that's all right?
- (void)didLoadFromCCB {
NSSet *numberSet = [NSSet setWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"gameScores"]];
NSArray *sortedNumbers = [[numberSet allObjects] sortedArrayUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"self" ascending:NO] ]];
NSNumber *secondHighest;
if ([sortedNumbers count] > 1){
secondHighest = sortedNumbers[1];
}
[_secondBiggestLabel setString:[NSString stringWithFormat:#"%ld",(long)secondHighest]];
}
`
EDIT : synchronize didn't help. Maybe I need to write something else to get access to NSUserDefaults from another one class?
When you set the object you have to follow it with a call to synchronize. That will actually save it.
[[NSUserDefaults standardUserDefaults] synchronize];
Are you sure you've initialized that '_scoresMutable' array?
Also, if the code from the below section is ran on a separate launch than when the first section of code is ran, it's possible you're terminating the app before the defaults can write to disk. Call 'synchronize' on the NSUserDefaults instance to fix that.

Public Array? Making array accessible by multiple classes

I am trying to save lessons in a day (from text-fields) into an array so that I can save them, and later display them on a new view.
My current code:
//monLessons = Monday's lessons
NSMutableArray *monLessons;
monLessons = [NSMutableArray arrayWithObjects: self.mon1.text, self.mon2.text, self.mon3.text, self.mon4.text, self.mon5.text, self.mon6.text, nil];
Cheers!
If it is just this one NSMutableArray that you want to access from multiple classes - NSUserDefaults would be the easiest and cleanest solution.
Example
So save the NSMutableArray:
[[NSUserDefaults standardUserDefaults]setObject:YOUR ARRAY forKey:#"MondayLessons"];
Now NSUserDefaults returns a immutable copy of the a array when you ask for it - you will need to return it like this:
NSMutableArray *yourArray = [[[NSUserDefaults standardUserDefaults]objectForKey:#"MondayLessons"] mutableCopy];
This way you get an NSMutableArray back and not an NSArray
Edit 2
I forgot to add:
Before you close your application or move to a new ViewController - you need to save the data to NSUserDefaults So please call - [[NSUserDefaults standardUserDefaults]synchronize];
Anytime you want to save. If you don't call this line of code - when you ask NSUserDefaults for your Array - it will be nil. You need to do this every time you make a change to the array you're saving.

If I use "registerDefaults" to register defaults, I can not remove the defaults which I registered

NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:#"content", #"myKey", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"myKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"myKey"]);
Log :
2012-12-17 17:09:05.062 browserHD[4075:c07] content
Why the result value "content"? I want the result value "nil".
Yes you are correct...
This may not be the perfect solution,. but a little bit of tweak to solve the problem.
If you use this way it works !!!
- (IBAction)set:(id)sender {
NSMutableDictionary *aDict=[NSMutableDictionary new];
[aDict setObject:_myText.stringValue forKey:#"key"];
[[NSUserDefaults standardUserDefaults] registerDefaults:aDict];
}
- (IBAction)remove:(id)sender {
NSMutableDictionary *aDict=[NSMutableDictionary new];
[aDict setObject:#"null" forKey:#"key"];
[[NSUserDefaults standardUserDefaults] registerDefaults:aDict];
}
- (IBAction)get:(id)sender {
NSLog(#"-> %#",[[NSUserDefaults standardUserDefaults]objectForKey:#"key"]);
}
The registerDefaults affects a different "level" of user defaults than the setObject:forKey: or the removeObjectForKey. It goes into the global user defaults which is a level higher than the standard user defaults. "Global" being a misnomer because it is still local to your app.
You cannot remove values from the global user defaults with this method.
Global Defaults (NSGlobalDomain)
-> User Defaults (NSRegistrationDomain)
If a value is in user values then it overrides the global value. If not then the value from Global Defaults is taken. Adding and removing values only affects the User Defaults level.
Apparently you cannot get rid of the global defaults because if you remove the user default the global one will always "shine through". But you could set the object value for something you want to "replace with nil" to [NSNull null]. Then in your code you'd check for this case: either the default is nil or it is [NSNull null] which would tell you that the value is not set.

How can i save objects, but not overwrite in Objective C?

Hello :)
How can i save objects, but not overwrite in Objective C,
i tried NSUserDefaults but when i add object, it will overwrite !
how can i prevent this, because i am trying to create a favorites in my app or bookmarks,
but i don't know how to save those objects i am trying to save.
This is when i am trying to save.
NSUserDefaults *favorite = [NSUserDefaults standardUserDefaults];
[favorite setObject:saveTip forKey:#"saveTipFavorite"];
[favorite synchronize];
But i overwrite every time i push add to favorite button in my app !
And i don't want it to overwrite, but make a new object and append it.
I hope you understand me :)
It is overwriting because there can only be one object per key, and you are changing it each time. What you want to do, is store an array instead of a single object, and set that as a key in your user defaults.
Initialization:
NSMutableArray *objectArray;
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSArray *oldSavedArray = [currentDefaults objectForKey:#"savedArray"];
if (oldSavedArray != nil)
objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
objectArray = [[NSMutableArray alloc] init];
Notice we are converting from NSArray to NSMutableArray because the user defaults can only store the immutable (NSArray) version.
Then to add an item:
[objectArray addObject:whatever];
[currentDefaults setObject:objectArray forKey:#"savedArray"];
If this is something you will be doing a lot (tons of data), you may consider using Core Data instead, it will be faster. NSUserDefaults is not really meant for storing heavy data.
The object you save can be an array. Create an array to save the tips and make that the object given to NSUserDefaults.
NSUserDefaults is fine for simple stuff, but if you want your App to handle significant amount of data, you will want to start using CoreData.
http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/CoreData/cdProgrammingGuide.html
Not only will this solve your saving problem, it will also make it easier to manipulate your data.

NSArray mutability and arrayByAddingObject

I thought I had a good understanding of Objects and mutability in Objective-C but I've noticed something curious with NSArray.
If I have the following that doesn't work:
NSArray *myArray = [ [[NSUserDefaults standardUserDefaults] arrayForKey:someKey] arrayByAddingObject:myObject ];
"myObject" is never added to "myArray".
However, the following works:
NSArray *someArray = [[NSUserDefaults standardUserDefaults] arrayForKey:someKey];
NSArray *myArray = [someArray arrayByAddingObject:myObject];
What's the explanation for this? I know that NSArray is not mutable but since it is during the initial assignment, it should work since either way seems equivalent.
[[NSUserDefaults standardUserDefaults] arrayForKey:someKey] returns an NSArray
someArray is an NSArray
And so, an NSArray is derived simply from [NSArray arrayByAddingObject:Object]
Thanks!
EDIT 1
I am simply wanting to store the NSArray back to NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setObject:myArray forKey:someKey];
It was never storing it properly, and so when I debugged I saw that "myObject" was never being added when the array was created.
Note: I have only been testing with [[NSUserDefaults standardUserDefaults] arrayForKey:someKey] returning a empty/nil array
EDIT 2
I've isolated the issue a bit; this only happens if [NSUserDefaults standardUserDefaults] arrayForKey:someKey] returns "nil" (basically, the array doesn't exist in NSUserDefaults).
I'm still curious to know though why it's not an issue for the 2nd code solution I have.
How are you checking to see if myObject is ever added? Both code examples look fine, and I've certainly used the former with no issues. But all of your assumptions are correct. The issue, if indeed there is one, lies elsewhere.
That should be the expected behaviour
If you call a method on nil in Objective-C, you always get nil (or NO/0) as your return value
In this case, when calling NSArray *myArray = [ [[NSUserDefaults standardUserDefaults] arrayForKey:someKey] arrayByAddingObject:myObject ];, if someKey isn't set in NSUserDefaults, then you're calling [nil arrayByAddingObject:] and so would expect to get nil back