views:

740

answers:

1

Hi, I can't find a cause for a memory leak in my application. I found out that there is a memory leak through instruments and than more times I call the function than more memory leaks occurs. So it is obvious that a memory leak takes place.

Here is my code. Object:

@interface WordObject : NSObject
{
    int word_id;
    NSString *word;
}

@property int word_id;
@property (copy) NSString *word;

@end

method being used for populating UITableView:

-(void) reloadTableData {
        [tableDataArray removeAllObjects];

        for (int i = 0; i <= 25; i++)
        {
         NSMutableArray *words_in_section = [ [NSMutableArray alloc] init];
         [tableDataArray addObject:words_in_section];
         [words_in_section release];
        }

        WordObject *tempWordObj;

        int cur_section;

        while ( tempWordObj = [ [WordsDatabase sharedWordsDatabase] getNext] )
        { 
         cur_section = toupper([ [tempWordObj word] characterAtIndex:0 ] ) - 'A';

         NSMutableArray *temp_array = [tableDataArray objectAtIndex:cur_section];
         [temp_array addObject:tempWordObj];
         [tableDataArray replaceObjectAtIndex:cur_section withObject:temp_array];
        }

        [mainTableView reloadData];

        [mainTableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
    }

getting content for cells:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CellFrame reuseIdentifier:cellIdentifier] autorelease];
    }


    WordObject *tempWordObj = [ [tableDataArray objectAtIndex:[indexPath section] ] objectAtIndex:[indexPath row] ];

    if (!tempWordObj)
    {
     return cell;
    }

    cell.text = [tempWordObj word];

    return cell;
}

here is how I clean up memory:

-(void) freeMemory
{   
    if (tableDataArray)
    {
     [tableDataArray release];
     tableDataArray = nil;
    }
}

function that is being called from reloadTableData:

    -(WordObject*) getNext {
    if(sqlite3_step(getStmt) == SQLITE_DONE)
    {
     sqlite3_reset(getStmt);
     return nil;
    }


    WordObject *tempWord = [ [WordObject alloc] init];
    tempWord.word_id = sqlite3_column_int(getWordsStmt, 0);

    tempWord.word = [NSString stringWithUTF8String:(char *)sqlite3_column_text(getWordsStmt, 1)]; //Here a leak occurs

    return [tempWord autorelease];
}

And the leaked objects is [WordObject word].

I will be very grateful to anyone who will help me to solve this issue.

+3  A: 

Add this method to WordObject:

- (void)dealloc {
    [word release];
    [super dealloc];
}

This code makes sure, that the property word is released when a WordObject instance is deleted.


I'm pretty sure that this code belongs in a dealloc method too. BTW, you don't need tableDataArray = nil.

- (void)freeMemory
{   
    if (tableDataArray)
    {
        [tableDataArray release];
        tableDataArray = nil;
    }
}
Georg
All instance variables are automatically zeroed when your class instance is allocated, so overriding init is unnecessary if all you're doing is zeroing your variables.
dreamlax
@gs: yes you should, nil is a shortcut for (id)0. It is the only way the runtime can guarantee that the receiver is valid or not.
dreamlax
@gs nil is equal to 0. You can count on that fact ;)
Jason Coco
Thank you very much!
Ilya
What's the point in `word = @"SomeString";`? it seems redundant - infact the whole init seems redundant. All that's needed to fix the leak is the dealloc that releases the string property.
Roger Nolan
The reason is, that I didn't know that all ivars are set to 0 when a new instance is allocated.
Georg