i have the following code which shows memory leak for object favorite near the statement with stringWithUTF8String.
i have declared favorites in the property
-(NSMutableArray *) readFavoritesFromDatabase
{
// Check if database is present
[self setDatabaseNameAndPath];
[self checkAndCreateDatabase];
// Setup the database object
sqlite3 *database;
//Initialize favorites array
if (favorites == nil)
{
[favorites release];
favorites = [[NSMutableArray alloc] init];
}
else
{
favorites = nil;
[favorites removeAllObjects];
}
// Open the database from the users file system
if(sqlite3_open([self.dataBasePath UTF8String], &database) == SQLITE_OK)
{
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "select * from Favorites";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
// Loop through the results and add them to the favorites array
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
// Create Favorite object and add it to the Favorite array
Favorite *favorite = [[[Favorite alloc] init] autorelease];
favorite.cameraID = [NSString stringWithUTF8String:(const char*)sqlite3_column_text(compiledStatement, 0)];
favorite.cameraName = [NSString stringWithUTF8String:(const char*)sqlite3_column_text(compiledStatement, 1)];
favorite.cameraLink = [NSString stringWithUTF8String:(const char*)sqlite3_column_text(compiledStatement, 2)];
[self.favorites addObject:favorite];
//[favorite.cameraID release];
// [favorite.cameraName release];
// [favorite.cameraLink release];
}
// If favorite cameras exists in database, then sort the Favorites array
if([self.favorites count]>0)
{
NSSortDescriptor *favoritesNameSorter = [[NSSortDescriptor alloc] initWithKey:#"cameraName" ascending:YES];
[self.favorites sortUsingDescriptors:[NSArray arrayWithObject:favoritesNameSorter]];
[favoritesNameSorter release];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
// Close the database
if(database !=nil)
{
sqlite3_close(database);
return self.favorites;
}
else
{
return nil;
}
}
Please let me know how to solve this memory leak problem
Thanks in advance.
Use this safe method:
Favorite *tempFavorite = [[Favorite alloc] init];
self.favorite = tempFavorite;
[tempFavorite release];
Normaly, in your Favorite dealloc function, you should remove all objects and clean what necessary before calling the super dealloc function.
Using this way, you don't need to worry about if favorite is nil or not since objective-c allows calling methods for nil objects
Regards
Meir Assayag
Not sure about the stringWithUTF8String leak, but this is a problem:
favorites = nil;
[favorites removeAllObjects];
You leak what was in favorites and then tell a nil object to remove all objects -- it's nil, by definition it has none. Then later on you try to add objects to it; that won't work either.
I don't see any leak in your stringWithUTF8String, that code works well. However, look at the whole method, I found something can create memory problems like leaking or crashing. If you already declared a property for favorites, then you should use self.favorites here
//Initialize favorites array
if (favorites == nil)
{
[favorites release];
favorites = [[NSMutableArray alloc] init];
}
else
{
favorites = nil;
[favorites removeAllObjects];
}
becomes:
//Initialize favorites array
if (self.favorites == nil)
{
self.favorites = [[NSMutableArray alloc] init];
}
else
{
self.favorites = nil;
}
It will help you a lot of things in memory managements, like in your else condition, you set the variable to nil but not release it, and in the first condition, you release a nil object?
Related
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
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I have memory leaks in the aTierOneData and when i tried [aTierOneData autorelease] , my app crashed.so how i can fix this memory leak.
Plese let me know
//===============================================================
- ( NSMutableDictionary * ) getDataToDisplayTierOne:(NSString*)dbPath{
//================================================================
NSMutableDictionary *aTierOneData = [[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)];
[aTierOneData setObject:aId forKey:aValue];
[aValue release];
[aId release];
}
}
}
else{//Even though the open call failed, close the database connection to
sqlite3_close(database);
}
return aTierOneData;
}
-(void)fetchDataForTierOne{
//===========================
myTierOneDict = [[NSMutableDictionary alloc]init];
myTierOneDict = [myDBOperations getDataToDisplayTierOne:[appDelegate getDBPath]];
NSArray *myTierOneDictKeys = [myTierOneDict allKeys];
myTierOneData = [[NSMutableArray alloc] initWithArray:(NSArray*)myTierOneDictKeys];
if ([myTierOneData count] > 0 ){
[self constructTierOnePicker];
}
}
You are leaking the sqlite3 object, because you don't call sqlite3_close on it when sqlite3_open succeeds.
Your method is named getDataToDisplayTierOne:. By Cocoa convention, that method should return an object that the caller does not own. So you should be sending autorelease to aTierOneData before returning it. If you want the caller to own the returned object, you should name the method something like newDataToDisplayTierOne: or mutableCopyDataToDisplayTierOne:.
We can't help you understand why your app crashes unless you show us the code that calls getDataToDisplayTierOne: and uses the returned dictionary.
Update
In fetchDataForTierOne, you are allocating/initing an empty NSMutableDictionary, storing a pointer to it in myTierOneDict, and then immediately leaking it by setting myTierOneDict to the return value of getDataToDisplayTierOne:. Why did you think you needed to store a pointer to an an empty dictionary in myTierOneDict?
The code you posted doesn't send release or autorelease to the dictionary created in getDataToDisplayTierOne:, so you might be leaking that dictionary also.
The code you posted doesn't send release or autorelease to the array that myTierOneData points to, so you might be leaking that also.
do
return [aTierOneData autorelease];
as cocoa naming convention, You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”. Your function name doesn't imply that this function create an object that is owned by you, so autorelease the return value. If you need to hold the data that is returned, take ownership of it by sending retain in your class.
In the function fetchDataForTierOne, first line myTierOneDict = [[NSMutableDictionary alloc]init]; is creating memory leak. You are creating a dictionary and assigned a different dictionary returned by getDataToDisplayTierOne function.
So, the dictionary created in the first line of function fetchDataForTierOne will become unreferenced and will create a leak. No need to write first line.
Second, return the dictionary with autorelease and retain it in fetchDataForTierOne function. After completing the usage release it.
Updated Code:
//===============================================================
-( NSMutableDictionary * ) getDataToDisplayTierOne:(NSString*)dbPath{
//================================================================
NSMutableDictionary *aTierOneData = [[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)];
[aTierOneData setObject:aId forKey:aValue];
[aValue release];
[aId release];
}
}
}
else{//Even though the open call failed, close the database connection to
sqlite3_close(database);
}
return [aTierOneData autorelease];
}
-(void)fetchDataForTierOne{
//===========================
myTierOneDict = [[myDBOperations getDataToDisplayTierOne:[appDelegate getDBPath]]retain];
NSArray *myTierOneDictKeys = [myTierOneDict allKeys];
myTierOneData = [[NSMutableArray alloc] initWithArray:(NSArray*)myTierOneDictKeys];
if ([myTierOneData count] > 0 ){
[self constructTierOnePicker];
}
[myTierOneDict release];
}
I want to load data to uipickerview from database.
this is my code
if (sqlite3_prepare_v2(UsersDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
int i=0;
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"select");
self.coun=[[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
NSLog(#"Coun = %#",coun);
self.animals=[coun componentsSeparatedByString:#":"];
NSLog(#"String value=%#",self.animals);
}
sqlite3_finalize(statement);
} else
{
NSLog(#"not select");
}
and button actions code is
- (IBAction)selectAnItem:(UIControl *)sender {
//Display the ActionSheetPicker
[ActionSheetPicker displayActionPickerWithView:sender data:self.animals selectedIndex:self.selectedIndex target:self action:#selector(itemWasSelected::) title:#"Select Country"];
}
but it run load only last value. Not all values loaded in UIpickerview. How to load all values from database using this code. Anyone pls help me. Thanks in advance.
You have to do like this,
NSArray *splitedString = [coun componentsSeparatedByString: #":"];
NSString *animalName;
if ([splitedString count]>0)
{
animalName=[splitedString objectAtIndex:0];
[self.animals addObject:animalName]; //here animals should be NSMutableArray
}
In the while loop, you have to collect all the self.coun values in an array. When you come out of the loop, having all the values, populate the picker.
NSMutableArray *countries = [[NSMutableArray alloc] init];
while (sqlite3_step(statement) == SQLITE_ROW){
self.coun=[[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
NSLog(#"Coun = %#",coun);
[countries addObject:coun];
//self.animals=[coun componentsSeparatedByString:#":"];
//NSLog(#"String value=%#",self.animals);
}
// Now you can use countries to populate in picker.
You have to implement data source and delegates for the UIPickerView.
Seems, you are storing countries in DB, reading from DB you are assigning in self.animals. Thats kind of not matching things with variable names. And why are your parsing by ":"?
I have an SQLite Database with 5000 rows that is loaded into a tableview.
It takes around 5-10 sec (which is extremely long on the iPhone) to load the table. Is there a way I can load the cells in smaller batches or something else to speed this up? Also, when I go back up in hierarchy then revisit this view, it has to reload all over again. Can I cache this out instead?
- (void)viewDidLoad
{
[super viewDidLoad];
[NSThread detachNewThreadSelector:#selector(myThread:) toTarget:self withObject:nil];
}
-(void) myThread:(id) obj {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *array = [[Database sharedDatabase] getICD9DiseaseCodes];
[self performSelectorOnMainThread:#selector(dataDoneLoading:) withObject:array waitUntilDone:NO];
[pool release];
}
-(void) dataDoneLoading:(id) obj {
NSMutableArray *array = (NSMutableArray *) obj;
self.codeAray = array;
[self.myTableView reloadData];
[self dismissHUD];
NSLog(#"done");
}
In my database class:
-(NSMutableArray *) getICD9DiseaseCodes
{
sqlite3 *database = CodesDatabase();
NSMutableArray *icd9DiseaseCodes = [[[NSMutableArray alloc] init] autorelease];
NSString *nsquery = [[NSString alloc] initWithFormat:#"SELECT code, title, description FROM icd9_disease_codes ORDER BY code"];
const char *query = [nsquery UTF8String];
[nsquery release];
sqlite3_stmt *statement;
int prepareCode = (sqlite3_prepare_v2( database, query, -1, &statement, NULL));
if(prepareCode == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW)
{
ICD9DiseaseCodes *code = [[ICD9DiseaseCodes alloc] init];
code.code = [NSString stringWithCString:(char *)sqlite3_column_text(statement, 0) encoding:NSUTF8StringEncoding];
code.name = [NSString stringWithCString:(char *)sqlite3_column_text(statement, 1) encoding:NSUTF8StringEncoding];
code.description = [NSString stringWithCString:(char *)sqlite3_column_text(statement, 2) encoding:NSUTF8StringEncoding];
[icd9DiseaseCodes addObject:code];
// NSLog(#"Code: %# Short Description: %# Long Description: %#", hcpcsCode.code, hcpcsCode.name, hcpcsCode.description);
[code release];
}
sqlite3_finalize(statement);
}
return icd9DiseaseCodes;
}
My first question is why do you use SQLite directly, and not Core Data? Core Data will do fast partial fetches from the data store for you, for free with no extra code on your part.
If you want to do the same thing manually with SQLite directly, then you are in for some heavy lifting code. You will need to use LIMIT and OFFSET in your SQL queries to fetch partial data, and extend your API to fetch only smaller sub-sets at a time.
Have you considered or looked into CoreData? CoreData has a lot of optimization for large recordsets.
Thanks.
James
hye all,
i have built a SQLite database and wanna to add into iphone app. already i have add it resource->add->x.sqlite and also add libsqlite3.0.dylib.framework but i don't know what is the showing code. I wanna to show the data in the db when user pressed button.
Can anyone help me to give an example on how the db can be view when button is press??
Here's some basic code to query the database:
-(NSArray*)names
{
NSString* query = [[NSString alloc] initWithString:#"SELECT name FROM sometablename;"];
sqlite3_stmt* statement;
int retval = sqlite3_prepare_v2(yourDatabaseHandle, [query UTF8String], -1, &statement, nil);
[query release];
if (retval != SQLITE_OK)
{
sqlite3_close(yourDatabaseHandle);
NSAssert1(0, #"Error querying table: %i", (retval ^ SQLITE_ERROR));
return nil;
}
NSMutableArray* values = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW)
{
const char* value = (const char*)sqlite3_column_text(statement, 0);
NSString* s = [[NSString alloc] initWithUTF8String:value];
[values addObject:s];
[s release];
}
sqlite3_finalize(statement);
return values;
}
You might want to present this in a table view. There are plenty of questions & answers here on Stack Overflow already to explain how to do that, as well as plenty of Apple sample code.