views:

54

answers:

4

Hi, I developing an application, in which i working with database manipulation. The method i have written in database class as follows.

-(NSMutableArray *)getData: (NSString *)dbPath{
    NSMutableArray *dataArray = [[NSMutableArray alloc] init];

    if(sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK){
        NSString *sqlQuery = [NSString stringWithFormat:@"SELECT empID, addText FROM Employee WHERE nameID = %@", nameID];
        sqlite3_stmt *selectstmt;
        if(sqlite3_prepare_v2(database, [sqlQuery UTF8String], -1, &selectstmt, NULL) == SQLITE_OK){

           while (sqlite3_step(selectstmt) == SQLITE_ROW){
                [dataArray addObject:[[NSMutableDictionary alloc] init]];

                [[dataArray lastObject] setObject:[NSString 
                                 stringWithFormat:@"%d", sqlite3_column_int(selectstmt, 0)] forKey:@"empID"];

                [[dataArray lastObject] setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt,1)] forKey:@"addText"];
            }
        }

        sqlite3_finalize(selectstmt);
    }
    sqlite3_close(database);
    return dataArray;
}

The above code work fine on the simulator but cannot on device. I also was tracing the memory leaks , in which i founding that memory leak in above method code. But i not able to solve the that memory leak.

Now i also find out memory leak in following method.

  • (id)initWithString:(NSString *)str attributes:(NSDictionary *)attributes

{ if ((self = [super init])) { _buffer = [str mutableCopy]; _attributes = [NSMutableArray arrayWithObjects:[ZAttributeRun attributeRunWithIndex:0 attributes:attributes], nil]; } return self; }

The leak near _buffer = [str mutableCopy];. And leak trace gives me in the output continuous increasing NSCFString string allocation. How i maintain it?

Thanks in advance.

+2  A: 

Your leak is that you don't release either the dataArray object, nor the mutable dictionaries you create in the while loop. Consider autoreleasing the mutable array, and manually releasing the dictionaries after you add them to the array.

As for why it "doesn't work" on the device, you need to be more specific about what happens and why that isn't what you expect.

Graham Lee
@Graham Lee, Thanks. you are saying that dataArray releasing should be manually. But we can not releasing the dataArray before return statement. If we releasing dataArray before return statement, we will loose all objects from dataArray right?
RRB
@rajb actually I said that you should autorelease `dataArray`, which avoids the problem you raise (which is indeed correct).
Graham Lee
@ Graham Lee, Thanks.NSMutableArray *dataArray = [NSMutableArray array]; this line would be auto releasing itself right?
RRB
That's correct.
Graham Lee
+1  A: 

From the first glance you have 2 places where leaks can be:

NSMutableArray *dataArray = [[NSMutableArray alloc] init];
...
return dataArray;

Caller method is responsible for releasing array returned from your method - check if it does.

Also your method name is not consistent with obj-c guidelines - they suggest that methods returning non-autoreleased object( so caller is responsible for releasing them) should contain create, alloc, copy in their name. So it could be better to return autoreleased array (return [dataArray autorelease]; from this method and let caller decide whether it needs to retain array or not.

Second place is

[dataArray addObject:[[NSMutableDictionary alloc] init]];

It is leaking dictionary object, you should probably just write

[dataArray addObject:[NSMutableDictionary dictionary]];
Vladimir
+1  A: 

Your inner loop leaks the NSMutableDictionary objects, as you should release them after adding to the array, i.e.

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:[NSString  stringWithFormat:@"%d", sqlite3_column_int(selectstmt, 0)] forKey:@"empID"];
[dict setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt,1)] forKey:@"addText"];
[dataArray addObject:dict];
[dict release];

Also, your whole method should most probably return an autoreleased object by naming convention. Not sure if this is a leak - depends on how you call that method and if you release the returned value.

So maybe use

return [dataArray autorelease];
Eiko
@Eiko, return[dataArray autorelease]; statement i used before but it not worked.Firstly it showing employee data, when i retrieving another row from employee table it will give "_kill" error.
RRB
@Eiko,Thanks.NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];[dict setObject:[NSString stringWithFormat:@"%d", sqlite3_column_int(selectstmt, 0)] forKey:@"empID"];[dict setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt,1)] forKey:@"addText"];[dataArray addObject:dict];[dict release]; Above stub is well working.
RRB
A: 

Your method contains two call to +alloc that don't have corresponding calls to -release or -autorelease.

NSMutableArray *dataArray = [[NSMutableArray alloc] init];
...
[dataArray addObject:[[NSMutableDictionary alloc] init]];

You can rewrite these lines like this to get rid of the leak:

NSMutableArray *dataArray = [NSMutableArray array];
...
[dataArray addObject:[NSMutableDictionary dictionary]];
jlehr
@jlehr, Thanks, please explain me the difference between NSMutableArray *dataArray = [NSMutableArray array]; and statement of NSMutableArray *dataArray = [[NSMutableArray alloc] init];?
RRB
NSMutableArray *dataArray = [NSMutableArray array]; statement is well working now.
RRB
The `+array` method returns an object created (conceptually at least) by calling `[[[NSMutableArray alloc] init] autorelease]`. The best way to get comfortable with memory management is to read Apple's excellent Memory Management Guide: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
jlehr