views:

218

answers:

3

Hi, in my application, a RSS reader, I get memory leaks that I can't fix because I can't understand from where they come from. Here is the code pointed out by Instruments.

-(void) readArticlesFromDatabase {

[self setDatabaseInfo];

sqlite3 *database;

articles = [[NSMutableArray alloc] init];

if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) { const char *sqlStatement = "select * from articles"; if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) { while(sqlite3_step(compiledStatement) == SQLITE_ROW) {

NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aDate = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aUrl = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSString *aCategory = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];
NSString *aAuthor = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 5)];
NSString *aSummary = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 6)];
NSMutableString *aContent = [NSMutableString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 7)];
NSString *aNbrComments = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 8)];
NSString *aCommentsLink = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 9)];
NSString *aPermalink = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 11)];

[aContent replaceCharactersInRange: [aContent rangeOfString: @"http://www.mywebsite.com/img/action-on.gif"] withString: @"hellocoton-action-on.gif"];
[aContent replaceCharactersInRange: [aContent rangeOfString: @"hhttp://www.mywebsite.com/img/action-on-h.gif"] withString: @"hellocoton-action-on-h.gif"];
[aContent replaceCharactersInRange: [aContent rangeOfString: @"hthttp://www.mywebsite.com/img/hellocoton.gif"] withString: @"hellocoton-hellocoton.gif"];

NSString *imageURLBrut = [self parseArticleForImages:aContent];    
NSString *imageURLCache = [imageURLBrut stringByReplacingOccurrencesOfString:@":" withString:@"_"];
imageURLCache = [imageURLCache stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
imageURLCache = [imageURLCache stringByReplacingOccurrencesOfString:@" " withString:@"_"];

NSString *uniquePath = [tmp stringByAppendingPathComponent: imageURLCache];
if([[NSFileManager defaultManager] fileExistsAtPath: uniquePath]) {
 imageURLCache = [@"../tmp/" stringByAppendingString: imageURLCache];
 [aContent replaceCharactersInRange: [aContent rangeOfString: imageURLBrut ] withString: imageURLCache];
}

Article *article = [[Article alloc] initWithName:aName date:aDate url:aUrl category:aCategory author:aAuthor summary:aSummary content:aContent commentsNbr:aNbrComments commentsLink:aCommentsLink commentsRSS:@"" enclosure:aPermalink enclosure2:@"" enclosure3:@""];

[articles addObject:article];

article = nil;
[article release];

} } sqlite3_finalize(compiledStatement);

} sqlite3_close(database); }

`

I have a lot of "Article" leaked and NSString matching with these using :

[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, X)];

I tried a lot of different code I always have these leaks. Anyone has got an idea to help me?

+1  A: 

You are leaking articles because:

article = nil;
[article release];

Why are you attempting to release nil?

Just remove the line setting article to nil, it is not needed. Given the above sample, there are probably a lot more problems in that code.

Paul Lynch
Thank you for your answer.I tried to add this because I am working on that point for a long time now and I am getting seek of that.As you said the problem does not come from that point (which change nothing (with or without) according to Instruments).You said there are lot more problems in that code, do you have any idea about why these lines create leaks :NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];Thank you for your time and your help.
Do8821
Removing the assignment to nil will stop your leaking articles.
Paul Lynch
You are also leaking the array "articles", and should release that at the end of the method. If you want to keep it as an instance variable, you should be using a property assignment.
Paul Lynch
Even without "article = nil;", it's still leaking "article". About the array "articles" i'm using it later and I need to remain it, so I release it in dealloc.
Do8821
A: 

I finally found a part of the solution by myself.

My mistake was to initialize the "articles" array INTO my function. Indeed, each time I called my function, I lost the previous data in this array. Now I initialize the "articles" array during launching and I simply remove its content in my function as that :

- (void)applicationDidFinishLaunching:(UIApplication *)application {
       // My Code
       articles = [[NSMutableArray alloc] init];
       // My Code
}

Then

-(void) readArticlesFromDatabase {

    [self setDatabaseInfo];
    sqlite3 *database;

    [articles removeAllObjects];

    if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
        const char *sqlStatement = "select * from articles";
        sqlite3_stmt *compiledStatement;
        if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
            while(sqlite3_step(compiledStatement) == SQLITE_ROW) {

                NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
                NSString *aDate = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
                NSString *aUrl = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
                NSString *aCategory = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];
                NSString *aAuthor = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 5)];
                NSString *aSummary = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 6)];
                NSMutableString *aContent = [NSMutableString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 7)];
                NSString *aNbrComments = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 8)];
                NSString *aCommentsLink = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 9)];
                NSString *aPermalink = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 11)];

                [aContent stringByReplacingOccurrencesOfString: @"http://www.mywebsite.com/img/action-on.gif" withString: @"hellocoton-action-on.gif"];
                [aContent stringByReplacingOccurrencesOfString: @"http://www.mywebsite.com/img/action-on-h.gif" withString: @"hellocoton-action-on-h.gif"];
                [aContent stringByReplacingOccurrencesOfString: @"http://www.mywebsite.com/img/hellocoton.gif" withString: @"hellocoton-hellocoton.gif"];

                NSString *imageURLBrut = [self parseArticleForImages:aContent]; 
                NSString *imageURLCache = [imageURLBrut stringByReplacingOccurrencesOfString:@":" withString:@"_"];
                [imageURLCache stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
                [imageURLCache stringByReplacingOccurrencesOfString:@" " withString:@"_"];

                NSString *uniquePath = [tmp stringByAppendingPathComponent: imageURLCache];
                if([[NSFileManager defaultManager] fileExistsAtPath: uniquePath]) {
                    imageURLCache = [@"../tmp/" stringByAppendingString: imageURLCache];
                    [aContent replaceCharactersInRange: [aContent rangeOfString: imageURLBrut ] withString: imageURLCache];
                }

                Article *article = [[Article alloc] initWithName:aName date:aDate url:aUrl category:aCategory author:aAuthor summary:aSummary content:aContent commentsNbr:aNbrComments commentsLink:aCommentsLink commentsRSS:@"" enclosure:aPermalink enclosure2:@"" enclosure3:@""];

                [articles addObject:article];

                [article release];
            }
        }
        sqlite3_finalize(compiledStatement);
    }
    sqlite3_close(database);
}

Now I have to focus on the "Article" leaks caused by [articles removeAllObjects]. If I don't remove all objects I don't have any leaks but if I do, I have got leaks. Any idea? How could I empty my array without leaking these Article Objects?

Do8821
A: 

I just spent the last few days tracking this down and below resolved the issue for me.

Adding a dealloc method to your articles NSObject and release all strings. Then in your readArticlesFromDatabase method first release articles and then do your init.

Kevin