views:

50

answers:

2

According to Instruments analysis, I have a memory leak here - and - I'm unsure as to how to properly release the scoresArray object that I have created.

This code does work properly, apart from the leakage. I release the highScoresArray object later in the code - but attempts to release the scoresArray kill the app. I thought that when I released highScoresArray, that I would release scoresArray, since they both point to the same location in memory. If anyone can point out where my thinking is flawed, that would be great.

- (void) readScoresFile {
    // Read the Scores File, if it exists
    NSString *filePath = [self scoresFilePath];
    // Only load the file if it exists at the path
    if ([[NSFileManager defaultManager] fileExistsAtPath: filePath]) {
        scoresFileExistsFlag = YES;
        NSLog(@"SCORES FILE EXISTS - THEREFORE LOAD IT");
        NSMutableArray *scoresArray = [[NSMutableArray alloc] initWithContentsOfFile: filePath];
        highScoresArray = scoresArray;
    } else {
        scoresFileExistsFlag = NO;
        NSMutableArray *scoresArray = [[NSMutableArray alloc] init];
        highScoresArray = scoresArray;

        // No Scores File exists - we need to create and save an empty one.
        int counter = 1;
        while (counter <= 5) {
            // Set up a date object and format same for inclusion in the Scores file
            NSDate *now = [[NSDate alloc] init];
            NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
            [dateFormat setDateFormat:@"yyyy.MM.dd"]; 
            NSString *theDateNow = [dateFormat stringFromDate:now];
            // Add the score data (Score and User and date) to the runScoreDataDictionary
            runScoreDataDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
                [NSNumber numberWithInt:0], @"score", 
                [NSNumber numberWithInt:0], @"landings",
                currentUser, @"user", 
                theDateNow, @"date", nil];
            //NSLog(@"Dictionary contains: %@", runScoreDataDictionary);
            // Add the dictionary to the highScoreArray
            [highScoresArray addObject:runScoreDataDictionary];
            //NSLog(@"OBJECTS in ARRAY: %i", [highScoresArray count]);

            [self writeScoresFile]; // Write the empty scores file to disk

            [now release];
            [dateFormat release]; 

            ++counter;

            //[scoresArray release]; // TESTING TO SEE IF THIS KILLS - YES KILLS
        }
    }
}
+1  A: 

I release the highScoresArray object later in the code - but attempts to release the scoresArray kill the app. I thought that when I released highScoresArray, that I would release scoresArray, since they both point to the same location in memory

As long as you haven't changed the highScoresArray pointer to point to another object, releasing it will be the same as releasing scoresArray.

NSMutableArray* highScoresArray;
NSMutableArray* scoresArray = [[NSMutableArray alloc] init];
highScoresArray = scoresArray;
[highScoresArray release]; // same as `[scoresArray release];`

But if you change either of them afterwards to point to another object, releasing them won't be equivalent:

NSMutableArray* highScoresArray;
NSMutableArray* scoresArray = [[NSMutableArray alloc] init];
highScoresArray = scoresArray;
// ... Now make `highScoresArray` point to another object ...
highScoresArray = [[NSMutableArray alloc] init];
// Now you should release both as they point to different objects.
[highScoresArray release];
[scoresArray release];

Of course, simply calling addObject doesn't alter the pointer. It changes the object being pointed to. Only reassigning the pointer to another object matters here.

Mehrdad Afshari
Thanks very much for your help.
ReachWest
+1  A: 

I'm guessing highScoresArray is an instance variable (since it's not declared anywhere in the method you listed). This means that upon creation of scoresArray (which is the same object as highScoresArray) it has a retain count of 1. You don't retain it, so releaseing it will decrement its retain count to 0 and it will be cleaned up -- not a good thing for an instance variable.

I'm also not sure why you do this:

NSMutableArray *scoresArray = [[NSMutableArray alloc] init];
highScoresArray = scoresArray;

You don't seem to need to use scoresArray anywhere else, so you could just do this:

[highScoresArray release];    // Release the old object
highScoresArray = [[NSMutableArray alloc] init];
mipadi
Yes - highScoresArray is a instance variable - I've eliminated the extraneous scoresArray - thanks for the input.
ReachWest