object not getting released in iphone - 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!

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

iphone memory leak with uitableview and sqlite

I am having a problem with what I believe is a memory leak which after some time is causing my app to slow down. I have a sectioned uitableview that has sections of 'movie directors' with rows of thier movies in their particular section. To do this I am calling a data object (and passing it the section header) to return that section's data and populate the section rows. So I am calling that object a few times on the same view(numberOfRowsInSection, cellForRowAtIndexPath, and didSelectRowAtIndexPath) this happens for each section. Looking at Instruments, I believe the leak is coming from getDirectorsMovies:theDirector from Movies.m. Can anyone tell me what I am doing that is causing this leak. Any help would be greatly appreciated, I've been working on this for a few weeks. Below is some code to show what I am doing.
Thanks in advance!!!
//Movies.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#import "Movie.h"
#interface Movies : NSObject {
}
- (NSMutableArray *) getDirectorsMovies:(NSString *)theDirector;
#end
//Movies.m //getDirectorsMovies:(NSString *)theDirector goes to the database, gets the directors movies, and returns them in an array
#import "Movies.h"
#implementation Movies
- (NSMutableArray *) getDirectorsMovies:(NSString *)theDirector
{
sqlite3 *database;
NSString *databaseName = #"Movies.sql";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSMutableArray *theDirectorsMovies = [[NSMutableArray alloc] init];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "select * from movies where lastname = ? order by lastname, movie";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_text(compiledStatement, 1, [theDirector UTF8String], -1, SQLITE_TRANSIENT);
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *aLastName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aDirector = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aMovie = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
Movie *movie = [[Movie alloc] initWithName:aMovie lastname:aLastName director:aDirector];
[theDirectorsMovies addObject:movie];
[movie release];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return theDirectorsMovies;
[theDirectorsMovies release];
}
#end
//Calling getDirectorsMovies:(NSString *)theDirector
MoviesAppDelegate *appDelegate = (MoviesAppDelegate *)[[UIApplication sharedApplication] delegate];
Director *director = (Director *)[appDelegate.director objectAtIndex:indexPath.section];//appDelegate.director IS A MSMutableArray defined in the AppDelegate
self.theMovies = nil;//THIS IS A MSMutableArray defined in the AppDelegate
Movies *directorMovies = [[Movies alloc] init];
self.theMovies = [directorMovies getDirectorMovies:director.lastname];
[directorMovies release];
Movie *movie = (Movie *)[theMovies objectAtIndex:indexPath.row];
//do whatever with the data
[movie release];
You have this:
return theDirectorsMovies;
[theDirectorsMovies release];
Nothing happens after the return statement, so your call to release will never happen. It was for this very reason that AutoreleasePools were invented (and patented). Simply do:
return [theDirectorsMovies autorelease];
And your memory leak will go away.
There are a number of potential issues here it would be useful to see the init method for Movie as that may be where the issue is. Also you should have an autorelease on the NSMutableArray.
In my sqlite code I have the following statement normally before the sqlite3_finalize call
sqlite3_clear_bindings(compiledStatement);
That call cleared up a lot of issues for my code.