How to store array of integer between app launches? - iphone

I want to store some data as a matrix of integers. For simplicity let's say I want to store this data in an array of integers. After each app launch I want to fill my model using this array. So the question is How to store arrays of integer in sandbox?
I don't want to write and rewrite data, maybe only once at first start.
What I tried:
I know about storing in plists and storing using NSCoding. But this strategies are used for more complicated models, not just arrays of integers.
EDIT:
is it faster to use c-arrays, storing them in txt-files and making own parser?

Plists and NSCoding are used for the simple integers as well.
However, you could just use the NSUserDefaults - that is the simples way:
[[NSUserDefaults standardUserDefaults] setObject:myArray forKey:#"AppData"];
Makes it easy to retrieve later from anywhere as well.

You can either store it in a plist, as you said, it's not a bad idea, it would work and do the job. It's not complicated at all, really, and not only used for complex models.
Else, you might want to use NSUserDefaults :
if (![NSUserDefaults standardUserDefaults] objectForKey:#"AKey"]) {
[[NSUserDefaults standardUserDefaults] setObject:yourArray forKey:#"AKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Don't forget that you need to wrap your integers into NSNumber.
A good practice for that would be using Objective-C's "new" notation : NSNumber * nb = #(42). That is much more readable that [NSNumber numberWithInt:42].
Good luck !
EDIT : According to your edit, no, don't use your own parser, at least for now. Don't try to optimize code when you don't really need it. Especially it it involves "breaking" Objective-C standards (and by that I mean using your own made stuff that might bug, and/or introduce strange behavior where Objective-C provides it's own way to do it). See this answer to know more about too much optimization.

+(void)storeArrayInDeviceWithKey:(NSArray *)arrData withKey:(NSString *)key{
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
[currentDefaults setObject:[NSKeyedArchiver archivedDataWithRootObject:arrData] forKey:key];
[currentDefaults synchronize];
}
For NSArray you need to little conversation with
NSKeyedArchiver archivedDataWithRootObject:UR OBJECT

Related

Best Way To Store Multiple Arrays Associated Together - Objective C

Throughout my iOS program. I create multiple arrays that all work together to make the program work. Now I need a method to store the arrays even when the iPhone is turned off. So I need these arrays to be stored like files that only I can touch.
I really would like to use User Defaults, but I just don't know if that is what I need. I have questions like:
How long will my data last in User Defaults?
When could you possibly lose the data?
If I was able to store arrays in User Defaults, how might I go about storing arrays in NSDictionaries? That way I could keep of my associated arrays together and give each array a specific key.
store array as NSData as in NSDefaults
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:urArray1] forKey:#"Array1"];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:urArray2] forKey:#"Array2"];
and read it as
NSData *dataRepresentingSavedArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"Array1"];
if (dataRepresentingSavedArray != nil)
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
I think that what you want is to store the arrays on the disk and then (when you actually need them) get them back. You can start by seeing if the objects inside your NSMutableArrays conform with the NSCoding protocol. You can then simply write them to disk and load them when you need. For that you can use NSKeyedArchiver class.
As #The Saad pointed, and well, you can store the arrays using that piece of code. Although I wouldn't recommend it. You can check #roronoa zorro answer, as well.
NSUserDefaults basically just a wrapper around property list serialization.
NSUserDefaults provides a programmatic interface to Mac OS X's
preferences system. preferences are actually stored to the disk, they
are written to the user's Library/Preferences/ directory with the file
name equal to the bundle identifier with a plist extension.
Take a look at MikeBeam's article here
Well NSuSerDefaults is a way of storing persistent data in iPhone and you don't have to worry about losing of data or about it's persisitency as long as the application remains on the iPhone.
Yes, you can store the NSDictionary object in NSUserDefaults but it is advisable to use it for small Data.For bigger data you can use sqlite or any other DB.
Here's the Tutorial For NSUserDefault

NSUserDefaults: Question about difference between two approaches

Problem
I want to store a NSString in NSUserDefaults and retrieve it later. I have a question about two different retrieving methods. Now at the top of the file I have:
// String used to identify the update object in the user defaults storage.
static NSString * const kLastStoreUpdateKey = #"LastStoreUpdate";
Method 1
NSString *lastUpdate = [[NSUserDefaults standardUserDefaults] objectForKey:kLastStoreUpdateKey];
Method 2
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *myString = [prefs stringForKey:kLastStoreUpdateKey];
Are there are significant differences I should know about? Also, can someone please explain what exactly is objectForKey? Apple's API states: that it "Returns the object associated with the first occurrence of the specified default." What exactly do they mean by the "specified default?
Thank you!
Generally you should use method 1.
that is "objectForKey".
Because, you know that, whatever you have stored in NSUserDefault. So, at the time of retriving it, you can catch the object with proper class like NSString, Array or any other user defined.
genrally "stringForKey" is not used.
If you are storing ingteger, BOOL into NSUserDefault then you should use intForKey, BOOLforKey, etc..
Cheers.

Save a set of integers iPhone

In my game I want to save a set of integers as statistics players can view. E.g number of deaths. This is an int I simply increase by one each time they get a game over.
How can I save this then have it at that number when I relaunch the game?
Thanks.
EDIT:
Ok after reading a few answers Im thinking writing to a plist is the way forward. I have been looking at tutorials but lets say I try this:
scoreData *score = [scoreData sharedData];
[dictionary setValue:score.highScore forKey:#"key2"];
[dictionary writeToFile:#"stats.plist" atomically:NO];
I have accessed my singleton with my score inside. Now when trying to setValue I get an error saying Im trying to convert an int to object.
Im not sure how else to approach it. It seems simple enough, however everywhere I look seem to give essentially the same approach.
Thanks for the help thus far, anymore is appreciated.
I would not abuse NSUserDefaults (Apple discouraged this at WWDC this year). Instead why not simply create an NSMutableDictionary and then store NSNumber objects in it. The MutableDictionary can easily be written to file and as is easily read in.
Any number of a lot of ways.
If you are only saving this and maybe a couple other simple things, using user defaults is probably the best idea.
If however, you are saving a lot more items than just a few, you may want to either use your own property list (if the number of items is less than 200 or so).
If you have a lot of settings, I generally advise folks to look at Core Data instead. It's fast with lots of items, whereas the other two, not so much.
Try...
[[NSUserDefaults standardUserDefaults] setInteger:highScore forKey:#"HighScore"];
highScore = [[NSUserDefaults standardUserDefaults] integerForKey:#"HighScore"];
You can write to a file (i.e. plain C functions fopen() etc), can use your own classes and use NS(Keyed)Archiver, or use NSUserDefaults to save data.

Is there a better way to put a bunch of stuff in NSUserDefaults?

I'm confused about NSUserDefaults on the iPhone.
I come from a C / asm background and the Objective-C stuff has been a learning experience.
I'm currently using NSUserDefaults to store some strings (for the names in a highscore table). I want to start implementing a "Save Game" type feature so if the user gets a call or exits out of the game for a moment, they can come back to it.
To recover the game, I've got a couple of BOOL flags, a couple of ints to store some necessary variables, but I'm stuck at an array I need to store.
I have a 50 element array of unsigned chars. I could move it to ints if it would make things easier, but I'm just not seeing it.
To work with NSUserDefaults I can setBool (already doing that), setFloat (again, already doing that), setInteger, and setObject.
Obviously I could declare keys for each element of the array and store them one by one with setInteger but that's really kludgy. What's the best way to tackle this? Instead of an array of unsigned chars, I somehow try to use an NSObject? Are there any good tutorials on NSObjects that I can read through to understand it better?
Would Property Lists fit better with what you are trying to achieve?
You can create dictionary, store value for each setting or an array, and then dump it to Property List. You can easily read them back or update the values based on keys.
http://developer.apple.com/documentation/Cocoa/Conceptual/PropertyLists/...
You can pass an NSArray or an NSDictionary to NSUserDefaults with setObject:forKey:. It works just fine. Obviously, your array of unsigned chars would have to become an an NSArray of NSNumbers, which implies some overhead, but it's probably your easiest option.
Try using an NSData object, which can be directly stored to NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:[NSData dataWithBytes:array length:len]
forKey:#"someArray"];
Whoa there, you should really look into using Core Data (or just sqllite) to store game state. NSUserDefaults is for what is says - defaults, configuration settings. It is not really meant to store largish chunks of binary data.
To convert a 50 element C array of unsigned chars in to an NSArray which you can store in a NSUserDefaults using:
NSMutableArray* a = [NSMutableArray new];
for ( int i = 0; i < 50; ++i ) {
[a addObject:[NSNumber numberWithInteger:yourArray[i]]];
}
[[NSUserDefaults standardUserDefaults] setObject:a forKey:#"theArray"];
[a release];
to get it back:
NSArray* a = [[NSUserDefaults standardUserDefaults] objectForKey:#"theArray"];
for ( int i = 0; i < 50; ++i ) {
yourArray[i] = [[a objectAtIndex:i] integerValue];
}
There is certainly no problem with using NSUserDefaults to store your game state, not when it is so small. If your game state was humoungous, you might want to investiage storing it as a plist file, but NSUserDefaults will not break a sweat handling this trivial amount of data.

inconsistant defaults (NSUserDefaults) behavior in iPhone simulator defaults

I've been experiencing very inconsistent results while developing an iPhone app and trying to save preferences via the standard NSUserDefaults mechanism. I am using code almost straight out of the iPhone Developer's Cookbook by Erica Sadun (fantastic book btw), it looks like this:
(void) updateDefaults
{
NSMutableArray *spells = [[NSMutableArray alloc] init];
NSMutableArray *locs = [[NSMutableArray alloc] init];
for (DragView *dv in [boardView subviews])
{
[spells addObject:[dv whichSpell]];
[locs addObject:NSStringFromCGRect([dv frame])];
}
[[NSUserDefaults standardUserDefaults] setObject:spells forKey:#"spells"];
[[NSUserDefaults standardUserDefaults] setObject:locs forKey:#"locs"];
[[NSUserDefaults standardUserDefaults] synchronize];
[spells release];
[locs release];
}
The values are saved, sometimes...and restored, sometimes. I can't get an exact bead on what does or does not make it work.
Does anyone else have any similar experiences? Any suggestions on what might make it work? Is the synchronize method the best way to force a disk write and make the values save, or is there something better (both for production, as well as simulator).
Thanks
Ryan
You should be using an NSKeyedArchiver for saving your arrays, such as:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:spells] forKey:#"spells"];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:locs] forKey:#"locs"];
[[NSUserDefaults standardUserDefaults] synchronize];
You should also make sure your spells class implements the NSCoding protocol (encodeWithCoder: and initWithCoder:), if it's a custom class. It looks like your locs are NSStrings, which will archive just fine.
You'll also need to do something like
NSData *dataRepresentingSavedSpells = [currentDefaults objectForKey:#"spells"];
if (dataRepresentingSavedSpells != nil)
{
NSArray *oldSpells = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedSpells];
}
To load the old values from the defaults.
I use synchronize to write to disk on exit, and it's been very reliable in my experience.
On Mac OS X, and probably also on iPhone OS, the defaults database can only contain property list objects: NSString, NSNumber, NSArray, NSDictionary, and NSData.
It's not clear from your code snippet what type a spell is, but if it isn't one of the above, it won't get stored in the defaults database. Your options are:
Write a method that will convert your object to and from a plist representation. In other words, a method to create an NSDictionary from your object and another method to initialize the object using an NSDictionary. You could also choose to store it as an NSArray or NSString.
Make your object implement the NSCoding protocol and then used NSKeyedArchiver to convert the object to an NSData object, and NSKeyedUnarchiver to convert it back.