views:

123

answers:

3

I would appreciate if someone could help me solve my leaking problem. The leaks occur at: aImage, aCategory, aDescription, category and categories. I release them in dealloc, but obviously that is not sufficient:

-(void) readListFromDatabase:(char *) sqlStatement {
    // Setup some globals
    databaseName = @"mydatabase.sql";

    // Get the path to the documents directory and append the databaseName
    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = [documentPaths objectAtIndex:0];
    databasePath = [documentsDir stringByAppendingPathComponent:databaseName];

    // Setup the database object
    sqlite3 *database;

    // Init the categories Array
    categories = [[NSMutableArray alloc] init];

    // Open the database from the users filessytem
    if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
        // Setup the SQL Statement and compile it for faster access
        sqlite3_stmt *compiledStatement;
        if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
            // Loop through the results and add them to the feeds array
            while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
                // Read the data from the result row
                aImage = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
                aCategory = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
                aDescription = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];

                // Create a new category object with the data from the database             
                category=[[Category alloc] initWithName:aImage category_name:aCategory description_text:aDescription];

                // Add the category object to the categories Array
                [categories addObject:category];

                [category release];
            }
        }
        // Release the compiled statement from memory
        sqlite3_finalize(compiledStatement);
    }
    sqlite3_close(database);

}

- (void)dealloc {
    [databaseName release];
    [databasePath release];
    [categories release];
    [aImage release];
    [aCategory release];
    [aDescription release];
    [category release];


    [super dealloc];
}
+2  A: 

If the method is called multiple times, then the strings will leak because you need to release the previous values. You also overrelease the strings in dealloc because you never retained them. You should write the assignments like this:

[aImage release];
aImage = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)] retain];

The only other way these strings could be leaking is if you are calling this method from a thread and you didn't create an auto release pool.

If the method is being called from a new thread, you need an autorelease pool:

- (void)myThreadFunction {
    NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
    try {
        // ...
        [self readListFromDatabase:whatever];
        // ...
    } @finally {
        [pool release];
    }

}
Mike Weller
I tried like this, but it keeps leaking (I retained the strings).NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString *myString = [NSString stringWithFormat:@"%@%@%@", @"select * from description where category ='", [category the_category], @"'"];char *composeSQL = ( char *) [myString cStringUsingEncoding:NSISOLatin1StringEncoding];readDescription=[[ReadFromDatabase alloc] init];[readDescription readListFromDatabase:composeSQL];description=[readDescription categories]; self.messageDetailViewController.arraySelectedCategoryValue = [description copy]; [pool release];
Darko Hebrang
I've updated my answer to include releasing the previous values in the instance variables. I can't see any other way that the strings are leaked.
Mike Weller
+1  A: 

Is that method that you posted being called more than once on the same object? If it is, categories from the first call will leak because it is overwritten each time readListFromDatabase: is called. Try:

// Init the categories Array
[categories release];
categories = [[NSMutableArray alloc] init];
JeremyP
I included [categories release]; but it still leaks. It seems that the leaking problem is harder to solve than to write the whole application.
Darko Hebrang
Why does the application terminate when I include [aImage autorelease] in the loop (it also terminates if [aImage release])?
Darko Hebrang
The last question you ask is easy to answer. It's because you do not own aImage. I think you need to rereead the Cocoa Memory Management Rules http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH
JeremyP
@Darko Hebrang: It terminates because your strings are not leaking. You need to retain or copy those if you want to use them later. Please do read the rules that JeremyP posted.
Jason Coco
A: 

Why does the application terminate when I include [aImage autorelease] in the loop (it also terminates if [aImage release])?

Darko Hebrang