Memory leak in Objective C - iphone

I am getting a potential leak in these methods..can anyone please help me..Leak in method 1 is in line 5..I am referencing this method from another class as [sync loginHandler] where sync is an object of the class which has the method loginHandler..
-(void) loginHandler
{
1 SCRMsugarsoap* service = [[SCRMsugarsoap alloc] initWithUrl:serverURL];
2 service.logging = YES;
3 service.username = userName;
4 service.password = password;
5 [service login:self action:#selector(sessionIdHandler:) user_auth: [[[SCRMuser_auth alloc] initWithUsername:userName andPassword:password]autorelease] application_name: #""];
6 [service release];
}
And another method where I have problems with leaks is
-(NSMutableArray *)searchContacts:(NSString *)tableName bySearchString:(NSString *)searchString
{
1 NSString *sid=#"";
2 NSString *firstname=#"";
3 NSString *lastname=#"";
4 NSString *qsql;
//NSArray *contactArray=[[NSArray alloc]init];
5 searchArray=[[NSMutableArray alloc]init];
6 qsql=[NSString stringWithFormat:#"SELECT DISTINCT sugar_id,first_name,last_name FROM CONTACTS where last_name LIKE '%%%#%%' OR first_name LIKE '%%%#%%' GROUP BY sugar_id ORDER BY last_name",searchString,searchString];
7 sqlite3_stmt *statement;
8 if (sqlite3_prepare_v2( db, [qsql UTF8String], -1, &statement, nil) == SQLITE_OK) {
9 while (sqlite3_step(statement) == SQLITE_ROW)
10 {
//TODO: alloc Contact object
11 Contact *contacts=[[Contact alloc]init];
12 sid = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
13 firstname = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
14 lastname = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 2)];
15
16 if ([firstname isEqualToString:#"(null)"]) {
lastname=[lastname stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[lastname substringToIndex:1] uppercaseString]];
17 contacts.lastName=lastname;
18 contacts.sugarId=sid;
19 contacts.firstName=#"";
}
20 else {
21 firstname=[firstname stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[firstname substringToIndex:1] uppercaseString]];
22 lastname=[lastname stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[lastname substringToIndex:1] uppercaseString]];
23 contacts.firstName=firstname;
24 contacts.lastName=lastname;
25 contacts.sugarId=sid;
}
26 [searchArray addObject:contacts];
//searchArray=[NSMutableArray arrayWithObjects:contacts];
//TODO: Release contacts variable
27 [contacts release];
28 [sid release]; //not sure about releasing these objects..just gave a try
29 [firstname release];
30 [lastname release];
31 firstname = nil;
32 lastname = nil;
33 sid=nil;
}
34 sqlite3_reset(statement);
}
35 sqlite3_finalize(statement);
36 return searchArray;
}
I am releasing searchArray in dealloc method. The leaks are between lines 5,11-14,16,21,22.These lines vary whenever I try to fiddle with the code..please help me guys..waiting for your suggestions..
I tried using instruments and these are the areas figured out using it..Can I also use build and analyze in xcode..I used that and made some changes to the code..
EDIT (Added methods that code 1 refers)
- (id) initWithUsername: (NSString*) username andPassword: (NSString*) pass
{
if(self = [super init])
{
Soap *converter = [[Soap alloc] init];
SCRMsugarsoap *service = [[SCRMsugarsoap alloc] init];
[service get_server_version:self action:#selector(get_server_versionHandler:)];
self.user_name = username;
self.password = [converter tomd5:pass];
[converter release];
[service release];
}
return self;
}
-(NSString*)tomd5:(NSString*)value{
const char *cStr = [value UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(cStr, strlen(cStr), result);
return [NSString stringWithFormat: #"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]
];
}

If searchArray is an instance variable, and you call searchContacts more than once, you will leak the previous value stored in searchArray.
You need to do something like...
[searchArray release];
searchArray=[[NSMutableArray alloc] init];
Sending messages to nil objects has no effect, so if searchArray hasn't been set, calling release will do nothing. On subsequent calls, you will release search array before letting go of the pointer to it.
Edit: Also, you are over releasing sid, firstName and lastName. Objects returned by class convenience methods like that are almost always returned autoreleased. Take a look at the Memory Management Guide

Well, from in the first method you allocate an SCRMuser_auth that you don't hold a pointer to so that object will definitely leak.
I am not quite sure in your second section of code but I will keep looking over it.

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

Unable to reload table giving EXC_BAD_ACCESS

while trying to reload table the program giving BAD_EXCESS Signal.
In below code.
-(void)textFieldDidEndEditing:(UITextField *)textField {
NSLog(#"%d",textField.tag);
if (textField.tag == 2) {
IntelligentPillBoxAppDelegate *appdelegate = (IntelligentPillBoxAppDelegate *)[[UIApplication sharedApplication]delegate];
appdelegate.strip1_detail = [pillboxDb get_detail_for_din:value];
[table reloadData];
}
[textField resignFirstResponder];
}
+(NSMutableArray*)get_detail_for_din:(int) din{
NSArray *arrDocPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *strDestPath = [NSString stringWithFormat:#"%#/samplepillbox1.sqlite",[arrDocPath objectAtIndex:0]];
//IntelligentPillBoxAppDelegate *appdelegate = (IntelligentPillBoxAppDelegate *)[[UIApplication sharedApplication]delegate];
//appdelegate.strip1_detail = [[NSMutableArray alloc]init];
NSMutableArray *strip1_detail = [[NSMutableArray alloc]init];
sqlite3 *db;
if(sqlite3_open([strDestPath UTF8String], &db)==SQLITE_OK)
{
NSString *query = [NSString stringWithFormat:#"select * from maintable_master where din =%d ",din];
void* v;
char* err_msg;
sqlite3_stmt *studentStmt;
if(sqlite3_prepare_v2(db, [query UTF8String], -1, &studentStmt, &err_msg)==SQLITE_OK)
{
while (sqlite3_step(studentStmt)==SQLITE_ROW) {
int din = sqlite3_column_int(studentStmt, 0);
NSString *brandname = [NSString stringWithUTF8String: sqlite3_column_text(studentStmt, 1)];
NSString *fullname = [NSString stringWithUTF8String: sqlite3_column_text(studentStmt, 2)];
NSString *strength = [NSString stringWithUTF8String: sqlite3_column_text(studentStmt, 3)];
NSString *medicationtype =[NSString stringWithUTF8String: sqlite3_column_text(studentStmt, 4)];
NSString *presciptionid= [NSString stringWithUTF8String: sqlite3_column_text(studentStmt, 5)];
//float marks = sqlite3_column_double(studentStmt, 2);
//pillbox *st = [[pillbox alloc]init];
//st.Din = sno;
//st.Name = sname;
//NSLog(#"%#",st);
Strip_items *si = [[Strip_items alloc]init];
si.Din = din;
si.BrandName = brandname;
si.FullName = fullname;
si.Strength = strength;
si.MedicationType = medicationtype;
si.PresciptionID = presciptionid;
NSLog(#"%#",si.BrandName);
NSLog(#"%d",si.Din);
NSLog(#"%#",si.FullName);
NSLog(#"%#",si.Strength);
NSLog(#"%#",si.MedicationType);
NSLog(#"%#",si.PresciptionID);
[strip1_detail addObject:si];
}
}
}
return strip1_detail;}
It seems you are not defining all your variables.
Check where value is defined and what its value is.
Also, perhaps you should first resign the responder of the text field and then reload the table view. Depending on your code, the text field whose first responder you resign might not exist any more after a table view reload.
enable zombie objects and it will tell you what error occured.
go to product>edit schems> enabl zombi objects
You are getting BAD_EXCESS in this line...
For more explanation post code of IntelligentPillBoxAppDelegate class
appdelegate.strip1_detail = [pillboxDb get_detail_for_din:value];

How to get ordered values from an unordered NSDictionary

I am trying to fetch and display contents from table.Currently i am running a query and store those id, and category name using NSMutableDictionary which works fine.
But I face one issue when i store the contents into NSMutableDictionary the order gets changed.When searching for this issue , it seems that this is the default behavior of the NSMutableDictionary.
I am not sure and how to use and what use to store the key pair value.
Please advice me that how can i overcome this problem
Thanks for stopping by...
//====================================================================
- ( NSMutableDictionary * ) getDataToDisplayTierOne:(NSString*)dbPath{
//====================================================================
NSMutableDictionary *aTierOneTemplateData = [[NSMutableDictionary alloc]init];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
const char *sql_query_stmt = "select * from main_categories";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql_query_stmt, -1, &selectstmt, NULL) == SQLITE_OK)
{
while(sqlite3_step(selectstmt) == SQLITE_ROW)
{
NSString *aValue = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(selectstmt, 1)];
NSString *aId = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(selectstmt, 0)];
[aTierOneTemplateData setObject:aId forKey:aValue];
[aValue release];
[aId release];
}
}
sqlite3_finalize(selectstmt);
}
sqlite3_close(database);
return aTierOneTemplateData;
}
Note : - I understand the limitations on using the nsmutabledictionery
so i expecting your advice to that how can i overcome / fetch id,
value in other way.please suggest
Updated
For example
Apple 1
Orange 2
Papaya 3
Actually i want that list to display it on my uitableview
Apple
Orange
Papaya
When tapping on each cell , i want to have its id value
for instance , i tap on Orange , now i want to have that id value as 2
Can you please tell me how to iterate over array of dictionery
Use NSMutableArray instead of NSMutableDictionary.
Change the declaration
NSMutableDictionary *aTierOneTemplateData = [[NSMutableDictionary alloc]init];
to
NSMutableArray *aTierOneTemplateList = [[NSMutableArray alloc]init];
And add the abjects to the array,
[aTierOneTemplateList addObject:aId];
And return the NSMutableArray,
return aTierOneTemplateList;
Edit:
If you modify the while loop as follows, you will get array of NSDictionarys with the same order.
NSString *aValue = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(selectstmt, 1)];
NSString *aId = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(selectstmt, 0)];
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:aValue,#"value",aId,#"key", nil];
[aTierOneTemplateList addObject:dict];
[dict release];
[aValue release];
[aId release];
Edit2:
Consider now in your tableviewcontroller, you have array of NSDictionarys (say aTierOneTemplateList).
In cellForRowAtIndexPath method,
NSDictionary *dict = [aTierOneTemplateList objectAtIndex:indexPath.row];
NSString *key = [dict objectForKey:#"key"];
NSString *value = [dict objectForKey:#"value"];
Similarly in didSelectRowAtIndexPath method.
Neither NSDictionary nor NSSet are ordered collections. If you want ordering, use NSArray. If you want to impose ordering, add objects to unordered collections that have their own index attribute.

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];

object not getting released in iphone

NSString *strSql = #"select tblrecentsearch_id,xmlrequest,company,postcode,city,kilometer,date from tblrecentsearch";
returnValue = sqlite3_prepare_v2(database, [strSql UTF8String], -1, &selectStatement, NULL);
if(returnValue == SQLITE_OK)
{
arrRecentSearch=[[NSMutableArray alloc] init];
while(sqlite3_step(selectStatement)==SQLITE_ROW)
{
Search *ObjSearch = [[Search alloc]init];
ObjSearch.intRecentSearchId = sqlite3_column_int(selectStatement, 0);
ObjSearch.xmlRequest = [NSString stringWithCString:(char *)sqlite3_column_text_check(selectStatement, 1) encoding:NSUTF8StringEncoding];
ObjSearch.strCompnay=[NSString stringWithCString:(char *)sqlite3_column_text_check(selectStatement, 2) encoding:NSUTF8StringEncoding];
ObjSearch.strPostCode=[NSString stringWithCString:(char *)sqlite3_column_text_check(selectStatement, 3) encoding:NSUTF8StringEncoding];
ObjSearch.strPlace = [NSString stringWithCString:(char *)sqlite3_column_text_check(selectStatement, 4) encoding:NSUTF8StringEncoding];
ObjSearch.strKilometer = [NSString stringWithCString:(char *)sqlite3_column_text_check(selectStatement, 5) encoding:NSUTF8StringEncoding];
ObjSearch.strDate = [NSString stringWithCString:(char *)sqlite3_column_text_check(selectStatement, 6) encoding:NSUTF8StringEncoding];
[arrRecentSearch addObject:ObjSearch];
[ObjSearch release];
}
}
sqlite3_finalize(selectStatement);
I want release arrRecentSearch but it will return from function . How can i realese this array. Please help me.I am fetching data from databse.
just autorelease it :
return [arrRecentSearch autorelease];
Have a look at the apple memopry management guidelines for more information on how this works
If you are going to return an autoreleased object, you must remember to retain it if you wnat to keep it around later. i.e. if we have a function that returns an autoreleased array
- (NSArray *) getSearchResults {
return [[[NSArray alloc] init] autorelease];
}
and you want to remember the search results for later you must remember to do this :
...
NSArray *results = [[self getSearchResults] retain]; //!< Remember the retain here!
...
or, you might use a property to store it :
#property (nonatomic, copy) NSArray *searchResults;
...
self.searchResults = [self getSearchResults]; //!< The property handles the retain for you here
...
Either way, if you just leave it as autoreleased, it's going to vanish and you're going to get an exception!
EDIT: Just realised MustISignUp has answered this in a comment!