Memory leaks in iphone application - iphone

Hi, guys! i'm newbie in iphone development. I have problems with the memory leak. I have such code.
do {
int s = sqlite3_step(statement);
switch (s) {
case SQLITE_ROW:{
Article *a = [[[Article alloc] init] autorelease];
for (int i = 0; i < columnCount; i++) {
const char *columnName = sqlite3_column_name(statement, i);
if(strncmp(columnName, "title", strlen("title")) == 0){
const char* colStr = (char*)sqlite3_column_text(statement, i);
if(colStr != NULL)
a.title = [[[NSString alloc] initWithCString: colStr encoding:NSUTF8StringEncoding] autorelease];
continue;
}
if(strncmp(columnName, "author", strlen("author")) == 0){
const char* colStr = (char*)sqlite3_column_text(statement, i);
if(colStr != NULL)
a.author = [[[NSString alloc] initWithCString:colStr encoding:NSUTF8StringEncoding] autorelease];
continue;
}
if(strncmp(columnName, "description", strlen("description")) == 0){
const char* colStr = (char*)sqlite3_column_text(statement, i);
if(colStr != NULL)
a.description = [[[NSString alloc] initWithCString:colStr encoding:NSUTF8StringEncoding] autorelease];
continue;
}
if(strncmp(columnName, "link", strlen("link")) == 0){
const char* colStr = (char*)sqlite3_column_text(statement, i);
if (colStr)
a.link = [[[NSString alloc] initWithCString:colStr encoding:NSUTF8StringEncoding] autorelease];
continue;
}
if(strncmp(columnName, "imageUrl", strlen("imageUrl")) == 0){
const char* colStr = (char*)sqlite3_column_text(statement, i);
if (colStr)
a.imageUrl = [[[NSString alloc] initWithCString:colStr encoding:NSUTF8StringEncoding] autorelease];
continue;
}
if(strncmp(columnName, "pubDate", strlen("pubDate")) == 0){
const char* colStr = (char*)sqlite3_column_text(statement, i);
if(colStr)
a.pubDate = [[[NSString alloc] initWithCString:colStr encoding:NSUTF8StringEncoding] autorelease];
continue;
}
}
[array insertObject:a atIndex:0];
}
break;
case SQLITE_DONE:
sqlite3_finalize(statement);
dataForReadingAvailable = NO;
break;
default:{
NSLog(#"getArticlesForFeed:sqlite3_step failed.Error:%s",sqlErrMsg);
return nil;
}
break;
}
}while(dataForReadingAvailable);
Tools from Xcode shows that i have leak memory when i a'm allocated object and when i initialized it properties. But why it's happens. All objects is autorealeased, so i think that will not to be such situation.
Thanks.

I think perhaps you overwrite the allocated memory with the new pointer somewhere.
I would replace
Article *a = [[[Article alloc] init] autorelease];
with
Article *a = [[Article alloc] init];
//some code
[a release]; //when you don't need it anymore
This is not a good practice to use autorelease much. It can even slow down your app btw in case of many objects.
And the strings like
a.title = [[[NSString alloc] initWithCString: colStr encoding:NSUTF8StringEncoding] autorelease];
I would replace with
a.title = [NSString stringWithCString:colStr encoding:NSUTF8StringEncoding];
In this case you also rely on autorelease pool, but it's much simpler.
EDIT:
Indeed, your 'Article' allocation is in the do-while loop.
In string [array insertObject:a atIndex:0]; your aray retains object and you don't need it anymore, but you rely on autorelease. Analyzer (or what tool you're using) sees, that you placed allocation in the cycle's body without releasing it after each iteration. This way, on the second iteration of the loop, you overwrite your "a" object, loosing the old pointer and leaking memory this way (pool won't find this pointer, since "a" overwritten). Even if you pass your loop only once, the analyzer does not care and gives you a warning.

Related

How to release an NSMutable Array which we need to use in return statements

IM USING SQLITE DATABASE for my iPhone app
In my app in data base to retried the content from the database i used an array and i return this array in a database method for select statement,
for this purpose i allocate an array and i need to release the array,
NSMutableArray *allContacts = [[NSMutableArray alloc] init];
return allContacts;
if i release an array how sh'd i used in return statement
viceversa if i tried to release after return (we can do anything after return)
Any solution please....
How should we use auto release NSMutable array
//Select statement for contacts
//==================================
+ (NSMutableArray*) selectAllContactsFromDB
{
NSString *DBPath = [self copyDBFile];
sqlite3 *contactsDB = nil;
sqlite3_stmt *statement = nil;
NSMutableArray *allContacts = [[NSMutableArray alloc] init];
if (sqlite3_open([DBPath UTF8String], &contactsDB) == SQLITE_OK)
{
NSString *query = [NSString stringWithFormat: #"SELECT ROWID, NAME, MOBILE, FROM CONTACTINFO"];
if(sqlite3_prepare_v2(contactsDB, [query UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
Contact *contact = [[Contact alloc] init];
contact.rowid = sqlite3_column_int(statement, 0);
contact.name = [NSString stringWithUTF8String:(const char*) sqlite3_column_text(statement, 1)];
contact.mobile = [NSString stringWithUTF8String:(const char*) sqlite3_column_text(statement, 2)];
[allContacts addObject:contact];
}
}
else {
NSLog(#"Statement not prepared");
}
}
[DBPath release];
return allContacts;
}
When you return an allocated object from a method pass it as an autoreleased object.
return [allContacts autorelease];
When you get an autoreleased object you need to retain it for further use:
So change the calling method like;
NSMutableArray *temp = [[YourClass selectAllContactsFromDB] retain];
try like this
NSMutableArray *allContacts = [[[NSMutableArray alloc] init] autorelease];
and also like this..
return [allContacts autorelease];
You can write return statement
return [allContacts autorelease];
OR you can use ARC in your project.
You will have to use autorelease :
return [allContacts autorelease];
This way il will be released the next time the autorelease pool will be flushed. And you have followed the golden rule : For each alloc, copy or retain, you must have a release or autorelease.
use ARC(Automatic Reference Counting) or you have a property as a mutuable array and just return the array...
to get u started on ARC, watch this: http://www.youtube.com/watch?v=FxuI4e_Bj58

trouble fixing memory leak iphone

i have 3 memory leaks in my application and i don't find how to fix it. I'm kind of new to xcode and objective c. Here is the code i have:
if(sqlite3_prepare_v2( [[DatabaseController sharedDatabaseController] getDb], sqlQueryConverted, -1, &dbStatement, NULL)==SQLITE_OK){
//Run the query
while ( sqlite3_step(dbStatement) == SQLITE_ROW )
{
const char *name = (const char *)sqlite3_column_text(dbStatement, 0);
int courseId = sqlite3_column_int(dbStatement, 1);
const char *location = (const char *)sqlite3_column_text(dbStatement, 2);
const char *date = (const char *)sqlite3_column_text(dbStatement, 3);
//Convert the returnedElement char to string
nameConverted = [[NSString alloc] initWithUTF8String:name];
locationConverted = [[NSString alloc] initWithUTF8String:location];
dateConverted = [[NSString alloc] initWithUTF8String:date];
Course *course = [[[Course alloc]initWithName:nameConverted _id:courseId location:locationConverted courseDate:dateConverted] autorelease];
//Add the course to the to a temporary list to remove duplicated items
[tempResults addObject:course];
}
[nameConverted release];
[locationConverted release];
[dateConverted release];
}
I have tried to autorelease it too. This code is being used to filter a search and reload a search display table. If i put the release line in the while statement the application would crash if i type 2 letters. How could i fix this?
Thanks.
EDIT: I've been going back and forth with this problem with no luck. I've come to the conclusion that there's something wrong with Instruments because it's still showing memory leaks. Here's the code as it is today and as i believe should fix the problem:
NSString *nameConverted = [[NSString alloc] initWithUTF8String:name];
NSString *locationConverted = [[NSString alloc] initWithUTF8String:location];
NSString *dateConverted = [[NSString alloc] initWithUTF8String:date];
Course *course = [[[Course alloc]initWithName:nameConverted _id:courseId location:locationConverted courseDate:dateConverted] autorelease];
//Add the course to the to a temporary list to remove duplicated items
[tempResults addObject:course];
course = nil;
[course release];
[nameConverted release];
nameConverted = nil;
[locationConverted release];
locationConverted = nil;
[dateConverted release];
dateConverted = nil;
NSLog(#"course retain count %i",[course retainCount]);
NSLog(#"name coverted retain count %i",[nameConverted retainCount]);
NSLog(#"location coverted retain count %i",[locationConverted retainCount]);
NSLog(#"date coverted retain count %i",[dateConverted retainCount]);
The logs are telling me that the retainCount = 0; so i don't understand why there's a memory leak. Can you guys give me some advice?
Thanks again.
You're leaking at each loop. You are only releasing the 3 lasts NSString. Everytime you re-assign a new NSString to your 3 variables (nameConverted, locationConverted, dateConverted) you loose the reference to the NSString objects they are pointing too. That means memory leaking. You only release the 3 last ones of them, when you get out of your While loop.
You are creating a memory block each while loop, and then only releasing it once. So if your while loop runs over 10 times, each string has a retain count of 10 but only released once.
To fix, put your 3 releases inside your while loop like this:
if(sqlite3_prepare_v2( [[DatabaseController sharedDatabaseController] getDb], sqlQueryConverted, -1, &dbStatement, NULL)==SQLITE_OK){
//Run the query
while ( sqlite3_step(dbStatement) == SQLITE_ROW )
{
const char *name = (const char *)sqlite3_column_text(dbStatement, 0);
int courseId = sqlite3_column_int(dbStatement, 1);
const char *location = (const char *)sqlite3_column_text(dbStatement, 2);
const char *date = (const char *)sqlite3_column_text(dbStatement, 3);
//Convert the returnedElement char to string
nameConverted = [[NSString alloc] initWithUTF8String:name];
locationConverted = [[NSString alloc] initWithUTF8String:location];
dateConverted = [[NSString alloc] initWithUTF8String:date];
Course *course = [[[Course alloc]initWithName:nameConverted _id:courseId location:locationConverted courseDate:dateConverted] autorelease];
//Add the course to the to a temporary list to remove duplicated items
[tempResults addObject:course];
[nameConverted release];
[locationConverted release];
[dateConverted release];
}
}
Have you tried to use:
nameConverted = [[NSString initWithUTF8String:name] autorelease];
locationConverted = [[NSString initWithUTF8String:location] autorelease];
dateConverted = [[NSString initWithUTF8String:date] autorelease];
And removing the releases outside the loop?
Also do not autoremove the course object, release it after adding it to tempResults.
This is how you should be doing it.
NSString *nameConverted = [[NSString alloc] initWithUTF8String:name];
NSString *locationConverted = [[NSString alloc] initWithUTF8String:location];
NSString *dateConverted = [[NSString alloc] initWithUTF8String:date];
Course *course = [[Course alloc] initWithName:nameConverted _id:courseId location:locationConverted courseDate:dateConverted];
[tempResults addObject:course];
[course release];
[dateConverted release];
[locationConverted release];
[nameConverted release];

How to solve Memory leaks for following Sqlite code?

I am getting memory leaks in Instruments in the following Sqlite Code.
NSArray *result = [self executeQuery:sql arguments:argsArray];
It calls following method.
- (NSArray *)executeQuery:(NSString *)sql arguments:(NSArray *)args {
sqlite3_stmt *sqlStmt;
if (![self prepareSql:sql inStatament:(&sqlStmt)])
return nil;
int i = 0;
int queryParamCount = sqlite3_bind_parameter_count(sqlStmt);
while (i++ < queryParamCount)
[self bindObject:[args objectAtIndex:(i - 1)] toColumn:i inStatament:sqlStmt];
NSMutableArray *arrayList = [[NSMutableArray alloc] init];
int columnCount = sqlite3_column_count(sqlStmt);
while ([self hasData:sqlStmt]) {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
for (i = 0; i < columnCount; ++i) {
id columnName = [self columnName:sqlStmt columnIndex:i];
id columnData = [self columnData:sqlStmt columnIndex:i];
[dictionary setObject:columnData forKey:columnName];
}
[arrayList addObject:[dictionary autorelease]];
}
sqlite3_finalize(sqlStmt);
return arrayList;
}
How do I solve it ?
We'd need to see the code of your executeQuery method - it should be returning an auto-released result, but perhaps it isn't.
You could try ;
NSArray *result = [[self executeQuery:sql arguments:argsArray] autorelease];
But I'd be wary of just blindly trying that without actually seeing what executeQuery does in detail.
EDIT:
OK, here's your problem;
NSMutableArray *arrayList = [[NSMutableArray alloc] init];
Either create it as an auto-released array, or finish the method with;
return [arrayList autorelease];

Memory Leak according to Instruments

Been running instruments on my app. Its says i am leaking 864bytes & 624bytes from 2 NSCFString and the library responsible is Foundation.
So that leads me to believe thats its not a leak caused by me? Or is it?
Here is the offending method according to instruments. It seems to be a
substringWithRange
that is leaking.
-(void) loadDeckData
{
deckArray =[[NSMutableArray alloc] init];
NSString* path = [[NSBundle mainBundle] pathForResource:#"rugby" ofType:#"txt"
inDirectory:#""];
NSString* data = [NSString stringWithContentsOfFile:path encoding:
NSUTF8StringEncoding error: NULL];
NSString *newString = #"";
NSString *newline = #"\n";
NSString *comma = #",";
int commaCount = 0;
int rangeCount = 0;
NSString *nameHolder = #"";
NSString *infoHolder = #"";
NSMutableArray *statsHolder = [[NSMutableArray alloc] init];
for (int i=0; i<data.length; i++)
{
newString = [data substringWithRange:NSMakeRange(i, 1)];
if ([newString isEqualToString: comma]) //if we find a comma
{
if (commaCount == 0)// if it was the first comma we are parsing the
NAME
{
nameHolder = [data substringWithRange:NSMakeRange(i-
rangeCount, rangeCount)];
}
else if (commaCount == 1)//
{
infoHolder = [data substringWithRange:NSMakeRange(i-
rangeCount, rangeCount)];
//NSLog(infoHolder);
}
else // if we are on to 2nd,3rd,nth comma we are parsing stats
{
NSInteger theValue = [[data
substringWithRange:NSMakeRange(i-rangeCount,rangeCount)]
integerValue];
NSNumber* boxedValue = [NSNumber
numberWithInteger:theValue];
[statsHolder addObject:boxedValue];
}
rangeCount=0;
commaCount++;
}
else if ([newString isEqualToString: newline])
{
NSInteger theValue = [[data substringWithRange:NSMakeRange(i-
rangeCount,rangeCount)] integerValue];
NSNumber* boxedValue = [NSNumber numberWithInteger:theValue];
[statsHolder addObject:boxedValue];
commaCount=0;
rangeCount=0;
Card *myCard = [[Card alloc] init];
myCard.name = nameHolder;
myCard.information = infoHolder;
for (int x = 0; x < [statsHolder count]; x++)
{
[myCard.statsArray addObject:[statsHolder
objectAtIndex:x]];
}
[deckArray addObject:myCard];
[myCard autorelease];
[statsHolder removeAllObjects];
}
else
{
rangeCount++;
}
}
[statsHolder autorelease];
}
Thanks for your advice.
-Code
As Gary's comment suggests this is very difficult to diagnose based on your question.
It's almost certainly a leak caused by you however, I'm afraid.
If you go to the View menu you can open the Extended Detail. This should allow you to view a stack trace of exactly where the leak occurred. This should help diagnose the problem.
When to release deckArray? If deckArray is a class member variable and not nil, should it be released before allocate and initialize memory space?

Memory alloc issues, crash on device iOS SDK 4.1(Thread 0 crash)

I have two problems
1) My App works fine on the device the first few times its run. Then it crashes after the First screen pops up(Tab BAr). If i connect the device to my MAC and then run the device app it works(not debug mode).
I Checked the crash Logs, it crashed cos of "EXC_BAD_ACCESS (SIGSEGV)" and Thread0 crashed.The error was NSAutorelease released a deallocated Object.
2) I ran the app using instruments on the simulator. It show a lot of leaks on this function call.
Here is a sample code. When i run it using Instruments it shows a leak on the "setObject" line.
//class A- subclass of NSObject
+(NSMutableDictionary *)Hello {
NSMutableDictionary *dctONE = [[NSMutableDictionary alloc]initWithCapacity:0];
NSMutableArray *arrKeys = [[NSMutableArray alloc] initWithCapacity:0];
[arrKeys addObject:#"Object1"];
[arrKeys addObject:#"Object2"];
[dctONE setObject:[NSString stringWithFormat:#"dsfsdf"] forKey:[arrKeys objectAtIndex:0]];
[dctONE setObject:[NSString stringWithFormat:#"dsfsdf"] forKey:[arrKeys objectAtIndex:1]];
[arrKeys release];
return dctONE;
}
/// class B
-(void)some_Function {
NSMutableDictionary * dct = [A Hello]; //all declarations are done
//do stuff with dct
[dct release];
}
WHy does it Leak at "setObject"?? I am releasing everything properly right? Only thing is the [NSString stringWithFormat:] but that is autorelease right??
This is driving me Crazy?
Are the two problems related??
PS: It Doesnt crash on the sim, and strangely doesnt crash even when i connect my device to my MAC and then test it on device(not debugging, directly clicking the app on the device)
EDIT:
-(NSMutableDictionary *) ExecuteDataSet:(NSString *)strQuery
{
NSMutableDictionary *dctResult = [[[NSMutableDictionary alloc] init] autorelease];
// BOOL isSucess = FALSE;
const char *sql = [strQuery UTF8String];
sqlite3_stmt *selectStatement;
//prepare the select statement
int returnValue = sqlite3_prepare_v2(database, sql, -1, &selectStatement, NULL);
if(returnValue == SQLITE_OK)
{
sqlite3_bind_text(selectStatement, 1, sql, -1, SQLITE_TRANSIENT);
//loop all the rows returned by the query.
NSMutableArray *arrColumns = [[NSMutableArray alloc] init];
for (int i=0; i<sqlite3_column_count(selectStatement); i++)
{
const char *st = sqlite3_column_name(selectStatement, i);
[arrColumns addObject:[NSString stringWithCString:st encoding:NSUTF8StringEncoding]];
}
int intRow =1;
while(sqlite3_step(selectStatement) == SQLITE_ROW)
{
NSMutableDictionary *dctRow = [[NSMutableDictionary alloc] init];
for (int i=0; i<sqlite3_column_count(selectStatement); i++)
{
int intValue = 0;
const char *strValue;
switch (sqlite3_column_type(selectStatement,i))
{
case SQLITE_INTEGER:
intValue = (int)sqlite3_column_int(selectStatement, i);
[dctRow setObject:[NSString stringWithFormat:#"%d",intValue] forKey:[arrColumns objectAtIndex:i]];
break;
case SQLITE_TEXT:
strValue = (const char *)sqlite3_column_text(selectStatement, i);
[dctRow setObject:[NSString stringWithCString:strValue encoding:NSUTF8StringEncoding] forKey:[arrColumns objectAtIndex:i]];
break;
default:
strValue = (const char *)sqlite3_column_value(selectStatement, i);
[dctRow setObject:[NSString stringWithCString:strValue encoding:NSUTF8StringEncoding] forKey:[arrColumns objectAtIndex:i]];
break;
}
}
[dctResult setObject:[dctRow retain] forKey:[NSString stringWithFormat:#"Table%d",intRow]];
intRow ++;
[dctRow release];
}
[arrColumns release];
}
return dctResult;
}
The leak appears to be in this line:
[dctResult setObject:[dctRow retain] forKey:[NSString stringWithFormat:#"Table%d",intRow]];
setObject will call retain on the object it stores, but you are actually retaining it manually, so its retain count will be 2 instead of 1, and when dctResult gets released, it won't be removed from memory.
You're doing a whole bunch of unnecessary work in +Hello. My first step at debugging is always to remove unnecessary complexity. Try it like this:
+(NSMutableDictionary *)Hello {
NSMutableDictionary *dctONE = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"dsfsdf", #"Object1", #"dsfsdf", #"Object2", nil];
return dctONE;
}
That NSMutableDictionary dictionaryWithObjectsAndKeys method takes a nil-terminated array that goes object, key, object, key. It returns an autoreleased NSMutableDictionary object, which is what you want to be returning.
There are no guarantees in this world, but I can darn near promise you that method won't leak.