views:

83

answers:

2

I would like to have at least 2 arrays which I can create when the user first saves something, and from then on read from the array when the user wants to view that data, and update the data when the user is done updating it.

Does a file need to be created before hand or how is this done on the device during runtime?

Just storing 2 arrays on the device somewhere with the correct path and loading/updating it when needed. I tried a few things, but couldnt seem to get it to work.

+1  A: 

I strongly suggest using some sort of database to persist such data, either Core Data or SQLite. With SQLite (my strong point), you can keep the database file open, saving changes to the array transactionally. There is very little chance of anything going wrong, thanks to SQLite's journalling mechanism and its staggeringly thorough testing regime. Core Data is built on SQLite, so the same guarantees apply.

EDIT (RE: comments):

Overkill is only an issue in situations where the cost of the solution is excessive for the problem being solved. SQLite is just sitting around asking to be used. First off, you can create a data structure to represent the data more meaningfully:

@interface Memo {
    NSString *title;
    NSString *textBody;
};
@property (nonatomic, retain) title;
@property (nonatomic, retain) textBody;
@end

@implementation Memo
@synthesize title, textBody;
@end

SQLite's raw interface is a bit clunky, so I'd save and load these using a C++ wrapper library to keep things simple:

- (NSString *)databasePath {
    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = [documentPaths objectAtIndex:0];
    // Choose a filename for your database.
    return [documentsDir stringByAppendingPathComponent:@"data.db"];
}

- (void)saveMemos:(NSArray *)memos {
    try {
        sqlite3_connection con([[self databasePath] cStringUsingEncoding:NSUTF8StringEncoding]);
        con.executenonquery("CREATE TABLE IF NOT EXISTS memo (i, title, textBody)");

        sqlite3_transaction trans(con);
        {
            sqlite3_command cmd(con,
                "INSERT INTO memo (i, title, textBody) VALUES (?, ?, ?)");
            for (int i = 0; i < memos.count; i++) {
                Memo *memo = (Memo *)[memos objectAtIndex:i];
                cmd.bind(1, i);
                cmd.bind(2, [memo.title cStringUsingEncoding:NSUTF8StringEncoding]);
                cmd.bind(3, [memo.textBody cStringUsingEncoding:NSUTF8StringEncoding]);
                cmd.executenonquery();
            }
        }
        trans.commit();
    } catch(exception &ex) {
        NSLog(@"SQLite3 error: %s", ex.what());
    }
}

- (NSMutableArray *)loadMemos {
    sqlite3_connection con([[self databasePath] cStringUsingEncoding:NSUTF8StringEncoding]);
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:10];
    if (con.executeint("SELECT COUNT(*) FROM sqlite_master WHERE name = 'memo'")) {
        sqlite3_command cmd("SELECT title, textBody FROM memo ORDER BY i");
        sqlite3_reader rd = cmd.executereader();
        while (rd.read()) {
            Memo *memo = [[Memo alloc] init];
            memo.text = [NSString stringWithFormat:@"%s", rd.getstring(0).c_str()];
            memo.titleBody = [NSString stringWithFormat:@"%s", rd.getstring(1).c_str()];
            [result addObject:memo];
        }
    }
    return result;
}

(WARNING: This code is totally untested.)

It is unlikely a home-grown file format will require any less code than this, and it will almost certainly be less robust.

You should also consider Core Data, but I haven't used it myself, so I can't offer assistance on that front.

Marcelo Cantos
let's say there is a note/memo, each memo has a title and a text body. I create a string as title^textBody and add the string to an array. This array of data needs to be stored somewhere( after each new note is added, the array must be updated and saved. when the program starts the array needs to be read so the user can see their saved notes. I think database is overkill for this small amount of data. How can this array, possibly more arrays of strings be saved during runtime. I tried writing to a plist, but it never stored the data after app exit.
alJaree
What do you mean by "overkill"?
Marcelo Cantos
I dont think it is necessary to implement a database for just 2 arrays? But I dont know, I am not sure how to do either so. How does one store 2 arrays? I have read NSKeyedArchiver, but am not sure how to implement it.
alJaree
Thanks for your trouble. appreciate it. I will try this technique and hopefully I get it right.
alJaree
NSUserDefaults is really, really easy to use to implement persistent data for your application, if your data is in NS* data structures like NSDictionary or NSArray. If your data is not too large then using NSUserDefaults is the way to go.
Bogatyr
@Bogatyr: That's a good suggestion. Why not add it as an answer?
Marcelo Cantos
Well, the answer was already selected. But OK, I'll add it as an answer
Bogatyr
reminder: _-[NSString stringByAppendingPathComponent:]_ returns an `autoreleased' string
Justin
Thank you for pointing that out, @Justin. I've amended the answer accordingly.
Marcelo Cantos
+1  A: 

NSUserDefaults is really, really easy to use to implement persistent data for your application, if your data is in NS* data structures like NSDictionary or NSArray. If your data is not too large then using NSUserDefaults is the way to go. I usually create a "save" method which I call from the app delegate's applicationWillTerminate, and a load method that I call from application:didFinishLaunchingWithOptions:

#define kThing1Key @"thing1"
#define kThing2Key @"thing2"
...

- (void) save
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    [defaults setObject:self.thing1 forKey:kThing1Key];
    [defaults setObject:self.thing2 forKey:kThing2Key];
    ...
    [defaults synchronize];
}

- (void) load
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    self.thing1 = [defaults objectForKey:kThing1Key];
    self.thing2 = [defaults objectForKey:kThing2Key];
    ...
}
Bogatyr