tags:

views:

982

answers:

4

If I want to store 2 strings, and ABContact image (or a variable to call the image) that persist even after restarting the application, which method should I use? NsMutableArray, plist or SQLite?

+4  A: 

An NSMutableArray will not persist after the application is restarted.

You may want to look at a plist that stores the two strings and a file URL pointing to the address book image that is cached in the application's Documents sandbox.

If you have lots of these to store and retrieve between application restarts, look into Core Data.

Alex Reynolds
Thank you so much! Actually what I need is 2 strings and 1 image URL to attach to 48 items, and between restarts, I don't hav to retrieve it immeodiately but probably befoe the game phase starts, I could have a loading phase right before and load all attributes? Please advise if there's a better method. And really appreciate your prompt response!
zerlphr
Wow, now that i look back, i realised how noobish my question was... Thanks everyone here!
zerlphr
+3  A: 

For very small amounts of data, like a few strings, but not an image, you could also use the much simpler NSUserDefaults. This is usually for saving preferences or some persistent data.

To save it:

[[NSUserDefaults standardUserDefaults] aString forKey:@"aStringKey];
if (![[NSUserDefaults standardUserDefaults] synchronize])
    NSLog(@"not successful in writing the default prefs");

To read it:

aString =  [[NSUserDefaults standardUserDefaults] stringForKey:@"aStringKey];

Again, I wouldn't go ahead and use this if what you really need is a database or a filesystem.

If you are putting in more data, and not enough to warrant an SQL database or Core Data, then I would write the data to a plist file. If all your data are objects, then I would do this:

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:kSavedDocFileName]; 
    NSMutableArray *myArrayToSave = [[NSMutableArray alloc] arrayWithCapacity: 48];
// 48 since you said in the comments that you have 48 of these
    for (int i = 0; i < 48; i++) {
     NSDictionary *myDict = [[NSDictionary alloc] initWithObjectsAndKeys:
          sting1[i], @"firstStr", //I'm assuming your strings are in a C array.
          string2[i], @"secondStr",// up to you to replace these with the right 
          url[i], @"myURL",  //way to access your 48 pieces of data
          nil];
     [myArrayToSave addObject:myDict];
     [myDict release];
    }
    if (![myArrayToSave writeToFile:path atomically:YES])
     NSLog(@"not successful in saving the unfinished game");

And you can read the data:

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:kMySavedDocName];
    NSArray *myLoadedData = [[NSArray alloc] initWithContentsOfFile:path];

    for (int i = 0; i < 48; i++) {
     NSDictionary *myDict = [myLoadedData objectAtIndex:i];
     string1[i] = [myDict objectForKey:@"firstStr"];
     string2[i] = [myDict objectForKey:@"secondStr"];
     url[i] = [myDict objectForKey:@"url"];

    }
    [myLoadedData release];

Make sure you don't just copy and paste this code since I just typed it in off the top of my head.

Now, if you don't want to mess with a dictionary, you could do that too. It's a little less elegant:

Save:

    NSMutableArray *myArrayToSave = [[NSMutableArray alloc] arrayWithCapacity: 48 * 3];
// 48 since you said in the comments that you have 48 of these three objects
    for (int i = 0; i < 48; i++) {
     [myArrayToSave addObject:string1[i]];
     [myArrayToSave addObject:string2[i]];
     [myArrayToSave addObject:url[i]];
    }
    if (![myArrayToSave writeToFile:path atomically:YES])
     NSLog(@"not successful in saving the unfinished game");

Load:

NSArray *myLoadedData = [[NSArray alloc] initWithContentsOfFile:path];

for (int i = 0; i < 48; i++) {
 string1[i] = [myLoadedData objectAtIndex:i * 3];
 string2[i] =  [myLoadedData objectAtIndex:i * 3 + 1];
 url[i] =  [myLoadedData objectAtIndex:i * 3 + 2];

}
[myLoadedData release];

Another important note is that in all these examples, I am assuming that you are dealing with objects (48 times 3 of them). That is why you can just add them to dictionaries and arrays and save them and reload them easily. If you were dealing with non-objects, like ints, or c strings or BOOLs, then you will have to use [NSNumber ...] to turn those into objects and then [object ...] to turn them back into non-ojects to begin with.

Try some of these, and then go find your app folder in ~/Library/Application Support/iPhone Simulator/Applications folder, and look in the Documents folder, open the file you have saved, and verify its contents. It's always reassuring to be able to check the data you write out - and to see how the different methods change the contents.

Good luck!

mahboudz
Thank you so much! Actually what I need is 2 strings and 1 image URL to attach to 48 items, and between restarts, I don't hav to retrieve it immeodiately but probably befoe the game phase starts, I could have a loading phase right before and load all attributes? Please advise if there's a better method. And really appreciate your prompt response!
zerlphr
Although I haven't seen any official numbers on stating the limits of NSUserDefaults, 48x3 strings (let's count the URL as a string) is probably more than reasonable.I modified my answer to include another way.
mahboudz
Thank you so much mahboudz! that's really really appreciated. thank you once again! will try it and post any problem if any.
zerlphr
Hi mahboudz, I read through your answers and codes but have another question: what if i wanna save only 1 item's attribute at a time instead of all 48 items?
zerlphr
If you want to save one set at a time, two ideas:- load the entire file into a mutable array, change the set (objectAtIndex:setIndex) you want, and write it all out- save each set as its own file (probably not the most elegant but you could use the set index or different names(strings) as filenames)First way sounds harder than it is.
mahboudz
+1  A: 

Don't do a database. It's way overkill for that little data. A plist would be fine. You should probably not use NSUserDefaults, I think that's right on the borderline of too much data for it. Just write a plist to the documents directory inside your application, and load it up when your application restarts. You can store an NSMutableArray in a plist, but it comes back to you as an NSArray. Just re-create it as a mutable array with [NSMutableArray arrayWithArray:] and retain it.

Kenny Winker
A: 

Hi mahbudz,

- (void)doneAceSpadeSetupClick:(id)sender {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *string1;
    NSString *string2;
    NSString *string3;
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"card1.plist"]; 
    NSMutableArray *myArrayToSave = [[NSMutableArray alloc] initWithCapacity: 1];
    //48 since you said in the comments that you have 48 of these

          NSDictionary *myDict = [[NSDictionary alloc] initWithObjectsAndKeys:
          string1, characterText.text, //I'm assuming your strings are in a C array.
      string2, actionText.text,// up to you to replace these with the right 
         string3, objectText.text,
         nil]; //iPhone simulator crashed at this line
        [myArrayToSave addObject:myDict];

    if (![myDict writeToFile:path atomically:YES])
        NSLog(@"not successful in saving the unfinished game");



    [self dismissModalViewControllerAnimated: YES];
}
zerlphr