views:

20

answers:

1

Hello, I am having trouble with persisting data.

Desired Behavior:

I have a text field defined in the view that captures user input. When the submit button is clicked (touch up inside), I expect to write that data to a mutable array. As of right now, I am going to archive that mutable array upon submit, but have also played with archiving once the view disappears/unloads. When a user navigates away from the view or exits the application and re-enters, I want to display the first element of that mutable array in the textfield.

Actual Behavior:

Textfield captures data and updates myMutableArray upon submitting. I have a few labels on the view plus NSLog to verify the count grows as I hit submit. I then archive this the first time, and I see that my file now exists in myDocuments plus when I revisit the view and check the count of dataArray, which is created if that file exists, the count of dataArray matches the number of elements I created in myMutableArray. If I start to enter in data again, it resets myMutableArray and dataArray all over again. That is one of a couple problems I think I have.

Questions:

If the file exists, then dataArray is created. Now I try to set the textfield to display the first element and the program bombs out! If dataArray exists, and I can see count is some positive value, I don't understand why I can't access that first element.

I feel like when I visit the view and go through this exercise, when I revisit the view I see I have dataArray present and with positive values, but when I start adding text again through the submit button, I reset everything! So I am persisting once maybe, but then wiping it clean. So much for real persistence. What am I doing wrong?

Eventually, I will be storing a record with a few elements. I will create multiple records over time for the user to review. Is archiving the best possible way? Should I start using NSCoding instead?

- (void)viewDidLoad {
    [super viewDidLoad];

    // Initialize mutable array and set equal to myMutableArray property

    NSMutableArray *aMutableArray = [[NSMutableArray alloc] init];
    myMutableArray = aMutableArray;

    // Debug Logging
    // NSLog(@"Mutable Array Count is: %i", [myMutableArray count]);

    NSFileManager *filemgr;
    NSString *docsDir;
    NSArray *dirPaths;

    filemgr = [NSFileManager defaultManager];

    // Get the documents directory

    dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    docsDir = [dirPaths objectAtIndex:0];

    // Build the path to the data file

    dataFilePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: @"data.archive"]];

    // Check if the file already exists

    if ([filemgr fileExistsAtPath: dataFilePath])
    {
        NSMutableArray *dataArray;

        dataArray = [NSKeyedUnarchiver unarchiveObjectWithFile: dataFilePath];
        myTextField.text = @"%@", [dataArray objectAtIndex:0];  // THIS BOMBS OUT MY PROGRAM FOR SURE IF INCLUDED!!!
        //myUpdatedMutableArray = dataArray;

        // Debug Logging

        NSLog(@"Mutable Array (dataArray) Count is: %i", [dataArray count]);
        //NSLog(@"The first value in the array is: %i", [dataArray objectAtIndex:0]);
    }
    [filemgr release];

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}



- (IBAction) mySubmitButtonPressed:(id)sender {

    // Debug Logging

    NSLog(@"Submit Button was Pressed!");
    NSLog(@"Mutable Array (myMutableArray) Count is: %i", [myMutableArray count]);

    // Create string from textfield and addobject to myMutableArray; check to see that myMutableArray grows in count

    NSString *myString = [[NSString alloc] initWithFormat:@"%@",myTextField.text];
    [myMutableArray addObject:myString];
    NSLog(@"Mutable Array (myMutableArray) Count is: %i", [myMutableArray count]);

    // More Debug Logging just using on-screen labels

    NSString *mySecondString = [[NSString alloc] initWithFormat:@"%i", [myMutableArray count]];
    myFirstLabel.text = myString;
    mySecondLabel.text = mySecondString;

    // Archive myMutableArray

    [NSKeyedArchiver archiveRootObject: myMutableArray toFile:dataFilePath];

    //[contactArray release];

}
A: 

There are many issues with this code.

To begin, you leak memory all over the place. Specifically here:

NSMutableArray *aMutableArray = [[NSMutableArray alloc] init];
myMutableArray = aMutableArray;

Which should really be:

self.myMutableArray = [NSMutableArray array];

After you unarchive the data, if you want to keep it in myMutableArray, simply do this:

[myMutableArray appendArray: dataArray];

Or just:

self.myMutableArray = dataArray;

You should never release singleton instances like the NSFileManager, so completely get rid of this one:

[fileMgr release];

Your code crashes because this is not valid code:

myTextField.text = @"%@", [dataArray objectAtIndex:0];

(It actually is valid code, but it will do something very different than you think)

This is not Python, so you will have to do this:

myTextField.text = [NSString stringWithFormat: @"%@",
    [dataArry objectAtIndex: 0]];

But that is really the same as:

myTextField.text = [dataArray objectAtIndex: 0];

Adding a string to your array in mySubmitButtonPressed can be done much simpler than you think. Just do this:

[myMutableArray addObject: myTextField.text];

You should really learn about autoreleased objects, memory management and what retaining properties actually do.

St3fan
Let me give this a whirl. I am a rookie, so I am learning the hard way, but appreciate the feedback. I'll try cleaning this up and see where I land and post-back. Thank you.
newDeveloper
I have updated my code. It is a lot cleaner now, and I no longer overwrite the persistence, it is maintained through user sessions.
newDeveloper