views:

97

answers:

2

I seem to be having a 1.19 KB leak somewhere in the following code. opening up the call tree in instruments, I have narrowed down the leaks to the following:

61.8% of the leaks are coming from +[NSString stringWithUTF8String:]

38.1% of the leaks are coming from +[NSNumber numberWithDouble:]

-(void) readMinesFromDatabase 
{
    NSLog(@" Setup the database object");
    sqlite3 *database;

    // Init the  Array
    northernMines = [[NSMutableArray alloc] init];
    nCentralMines = [[NSMutableArray alloc] init];
    centralMines = [[NSMutableArray alloc] init];
    southernMines = [[NSMutableArray alloc] init];
    //NSLog(@" pre if statement");
    // 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
    const char *sqlStatement = "SELECT * FROM mines";
    //NSLog(@"pre 2nd if statement");
    sqlite3_stmt *compiledStatement;

    if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) != SQLITE_OK) 
{
        NSLog( @"Error: Failed to prepare stmt with message %s", sqlite3_errmsg(database));
    }
    else 
{
        // Loop through the results and add them to the feeds array
        NSLog(@"pre loop");
        while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
            NSString *name;
            NSString *com;
            NSString *county;
            NSNumber *lat;
            NSNumber *longit;
            // Read the data from the result row
            //deals with null strings in the name and commodity fields of the database
            //NSLog(@"ered the loop");
            if (sqlite3_column_text(compiledStatement, 3) != NULL) {
                name = [NSString  stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
            } 
            else {
                name = @"";
            }
            if (sqlite3_column_text(compiledStatement, 10) != NULL) {
                com = [NSString  stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 10)];
            } 
            else {
                com = @"";
            }
            //latitude and longitudes
            lat = [NSNumber numberWithDouble:(double )sqlite3_column_double(compiledStatement, 4)];
            longit = [NSNumber numberWithDouble:(double )sqlite3_column_double(compiledStatement, 5)];
            //NSLog(@"long %@",longit);
            // Create a new  object with the data from the database
            Mine *mine = [[Mine alloc] initWithMineName:name latitudeInitial:lat longitudeInitial:longit commodity:com];

            // Add the object to the animals Array
            county = [NSString  stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 8)];

            if([county isEqualToString:@"Butte"] || [county isEqualToString:@"Plumas"] || [county isEqualToString:@"Yuba"] || [county isEqualToString:@"Sierra"])
            {
                [northernMines addObject:mine];
            }
            else if([county isEqualToString:@"Nevada" ]|| [county isEqualToString:@"Placer"] || [county isEqualToString:@"El Dorado"] || [county isEqualToString:@"Sutter"])
            {
                [nCentralMines addObject:mine];

            }
            else if([county isEqualToString:@"Amador"] || [county isEqualToString:@"Sacramento"] || [county isEqualToString:@"Calaveras"] || [county isEqualToString:@"San Joaquin"] || [county isEqualToString:@"Stanislaus"])
            {
                [centralMines addObject:mine];
            }
            else if([county isEqualToString:@"Tuolumne"] ||[county isEqualToString:@"Mariposa"] || [county isEqualToString:@"Madera"] || [county isEqualToString:@"Merced"])
            {
                [southernMines addObject:mine];
            }
            else
            {

            }
            [mine release];
            //[name release];
            //[com release];
            //[county release];                        
            //[lat release];
            //[longit release];

        }
        NSLog(@"done with loop");
        //[mines addObject:@"nil"];

    }
    // Release the compiled statement from memory
    sqlite3_finalize(compiledStatement);


}
sqlite3_close(database);
}

the mine object implementation file is:

#import "Mine.h"

@implementation Mine
@synthesize mineName, latitudeInitial, longitudeInitial, commodity;
-(id)initWithMineName:(NSString *)n latitudeInitial:(NSNumber *)l longitudeInitial:(NSNumber *)g commodity:(NSString *)c 
{
    self.mineName = n;
    self.latitudeInitial = l;
    self.longitudeInitial = g;
    self.commodity = c;
    return self;
}

@end
+1  A: 

Well, it is a little hard to tell because of the indentation where the function ends (is this the entire function?) but I believe you are forgetting to release the 4 arrays that you are allocating at the beginning of the function. By leaking the arrays you are also leaking their contents.


Edit - for the initializer code you added:

I am not sure if this has anything to do with the memory leaks but I noticed that the initializer is not implemented correctly:

  • you should call init on super and update self (more details here)

  • of this I am not 100% sure, but I think you should not send messages (call methods) to the current object from inside the init method, and by using the dot notation you are actually calling the setter methods (but again, I am not really sure of this one)

I suppose that the properties are declared as (retain) and that you release them in the dealloc method. Which would be correct.

I can't really see anything else wrong with the code you showed. Maybe the problem is not exactly here (just an idea).


Edit 2 - example initializer

You should spend some time reading the Apple documentation, it has plenty of examples.

Here is my version (I hope it doesn't have too many mistakes):

-(id)initWithMineName:(NSString *)n latitudeInitial:(NSNumber *)l longitudeInitial:(NSNumber *)g commodity:(NSString *)c {

    // Assign self to value returned by super's designated initializer

    // Designated initializer for NSObject is init

    self = [super init];

    if (self) {

        mineName = [n retain];
        latitudeInitial = [l retain];
        longitudeInitial = [g retain];
        commodity = [c retain];

    }

    return self;
}
Florin
no these arrays are created intentionally to be used later in the program. if you notice, 15% of the memory leaks can be attributed to each property of the Mines object, in addition to the county NSString.
kevin Mendoza
I don't really understand the 15% you are talking about...Another idea: are you calling this method more than once? If you are calling it multiple times you will leak the previous arrays.
Florin
oh wait, nvm, my math was off. No this method is called only once during the program, in the appDelegate. Bear in mind that the database that This is loading contains 17,000 entries, each with 5 columns, so I dont think I can attribute the 1.19 KB to leaked arrays.
kevin Mendoza
Could you also post an example on how I would update the initializer to implement it correctly? I also must add that thought the callout tree places the leak inside this method, in instruments I dont see the leak occuring until later in the program, where the application would not have direct access to this method.
kevin Mendoza
update: I implemented the object code, and it works just as well as before. I'll use the new object code of course, and I think i'll edit the app to use coreData. Perhaps that will eliminate the leaks.
kevin Mendoza
A: 

Just a thought, but could the memory leak be in the Mine object initializer ( -[Mine initWithMineName: latitudeInitial: longitudeInitial: commodity:] ) ??

RichB
it is possible. Would posting the implementation file for the Mine object be helpful?
kevin Mendoza
I'd second what Florin says about tidying up the Mines initializer, but there is no memory leak there that I can see. Nor in the readMinesFromDatabase function. As a next guess could the memory leak tool be reporting the autorelease'd variables as leaks before the memory pool has been drained ?
RichB
its possible, but I cant think of anything that would require 1.19KB of allocation. the Sql database is several hundred kilobytes, so you can see my confusion.
kevin Mendoza