Deepak ML
Deepak ML

Reputation: 79

Memory leak detection using instruments

I am trying to figure out where is memory leaked in this piece of code ?

- (NSMutableArray *) fetchAidDetails:(NSNumber *) rowID {
    NSMutableArray *list = [[NSMutableArray alloc] init];    
    FMDatabase *db = [[FMDatabase databaseWithPath:[self dbPath]] retain];
    if(![db open]) {
        [db release];        
        return [list autorelease];
    }

    NSString *query = [NSString stringWithFormat:@"select legislative_type, legislative_name from legislative_aid where official_id = %d", rowID.unsignedIntValue];

    FMResultSet *result = [[db executeQueryWithFormat:query] retain];

    while ([result next]) {
        NSMutableDictionary *item = [[NSMutableDictionary alloc] init];        
        NSString *type = [[NSString alloc] init];
        type = [result stringForColumn:@"legislative_type"];
        [item setObject:type forKey:@"legislative_type"];
        [type release];

        NSString *party = [[NSString alloc] init];
        party = [result stringForColumn:@"legislative_name"];
        [item setObject:party forKey:@"legislative_name"];
        [party release];

        [list addObject:item];
        [item release];
    }

    [result release];
    [db close];
    [db release];

    return [list autorelease];
}

[item retainCount] gives 2 before [item release] and [list autorelease] will make the reference count 0, am i going something wrong here ?

Please help.

Thank you

Upvotes: 0

Views: 176

Answers (2)

AliSoftware
AliSoftware

Reputation: 32681

  • Dont rely on retainCount. The system or the internal code of the classes can retain your object internally and release it later, that's their business and you can't know, so you don't really know what value to expect in retainCount. That's not the good way to search for leaks

  • At multiple times in your code, you allocate an object (in your case an NSString), then ignore it to override the variable with some other value:

    NSString *party = [[NSString alloc] init]; // You allocate memory for an NSString object
    party = [result stringForColumn:@"legislative_name"]; // then you completely forget about it and override your party variable with a different object
    

Thats quite like if you were doing:

int i = 5;
i = 12;

Of course the first value is useless and not needed. But in the case of your code, this value that you never uses allocate memory that is never reclaimed so it leaks.

  • Then after your affected another object to your party variable, you later send a release to this new object. But party contains an autoreleased object already, as you affected [result stringForColumn:xxx] to it, and according to code naming conventions, this method returns an autoreleased object. So you do not need to send a release on this new object.

So your loop should simply look like the following instead:

while ([result next])
{
  @autoreleasepool {
    NSMutableDictionary *item = [[NSMutableDictionary alloc] init];        
    NSString *type = [result stringForColumn:@"legislative_type"];
    [item setObject:type forKey:@"legislative_type"];

    NSString *party = [result stringForColumn:@"legislative_name"];
    [item setObject:party forKey:@"legislative_name"];

    [list addObject:item];
    [item release];
  }
}

Upvotes: 0

Rengers
Rengers

Reputation: 15228

NSString *type = [[NSString alloc] init];
type = [result stringForColumn:@"legislative_type"];

You are creating an NSString 'type' which has a retain count of one, but then assign a different object to it. Remove the first line and just use this:

NSString *type = [result stringForColumn:@"legislative_type"];

You also need to remove the [type release] since stringForColumn returns an autoreleased NSString (at least if it adheres to the Cocoa naming conventions).

Upvotes: 1

Related Questions