Can anybody help me out why this piece of code is leaking and how can we handle it?
sqlite3 *database;
if (pickerList) {
self.pickerList=nil;
[pickerList release];
}
self.pickerList=[[NSMutableArray alloc] init];
NSString *dbPath = [self applicationDocumentsDirectory];
dbPath=[dbPath stringByAppendingPathComponent:#"database"];
dbPath=[dbPath stringByAppendingPathComponent:#"OFFENDERSDB.sqlite"];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
if (isAlertForViolationPicker) {
const char *sqlStatement = "SELECT * FROM VIOLATIONS_TBL";
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *recSTR=[[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
[self.pickerList addObject:recSTR];
[recSTR release];
recSTR=nil;
}
}
//[tempRowArray release];
sqlite3_finalize(compiledStatement);
//sqlite3_reset(compiledStatement);
sqlite3_close(database);
}
else {
const char *sqlStatement = "SELECT * FROM PLAN_TBL";
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *recSTR=[[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
[self.pickerList addObject:recSTR];
[recSTR release];
recSTR=nil;
}
}
sqlite3_finalize(compiledStatement);
sqlite3_close(database);
}
}
sqlite3_reset(compiledStatement);
recSTR is leaking in this case and I have tried all the below mentioned solutions but none worked (updated the code)
Thanx in advance
It looks as though you may be leaking pickerList. You have a pointer to pickerList which you then set to nil. Then you send a release message to this point (which is in effect a no-op). If you use:
if (pickerList)
{
[pickerList release];
self.pickerList=nil;
}
instead of your current code, do you fare any better? Without seeing more code it's hard to say, but you definitely want to release before you set the ivar to nil. (This said if you you've done #property (retain) UIPickerList *pickerList then self.pickerList = nil will release pickerList. If you've done this then your [pickerList release] call is redundant.)
You may well get a report of a recSTR leaking from instruments. But that doesn't mean that the issue isn't with pickerList. Looking at the code, it would not unlikely that recSTR is owned by an instance of pickerList that is hanging around because you've discarded the pointer to it and then sent a release message to nil. So you'll end up with a leak of recSTR and pickerList.
Related
i am using this code to insert names to table,i have a problem that after 150 +/- names the app crash with this log:
Received memory warning. Level=1
Received memory warning. Level=2
this is the code,did i done something wrong?
if (sqlite3_open([dataPath UTF8String], &database) == SQLITE_OK) {
for (int i = 0 ; i < count; i++) {
sqlite3_stmt *insertStmt = nil;
NSString *name = [song valueForProperty:MPMediaItemPropertyTitle];
if(insertStmt == nil)
{
NSString *statement = [NSString stringWithFormat:#"INSERT INTO Songs (name) VALUES (?)"];
const char *insertSql = [statement UTF8String];
if(sqlite3_prepare_v2(database, insertSql, -1, &insertStmt, NULL) != SQLITE_OK){
NSLog(#"Error while creating insert statement.");
insertStmt = nil;
continue;
}
sqlite3_bind_text(insertStmt, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(insertStmt)){
NSLog(#"Error while inserting data.");
insertStmt = nil;
continue;
}
else{}
sqlite3_reset(insertStmt);
insertStmt = nil;
}
[delegate IPodLibraryFinishEntity:self];
}
sqlite3_close(database);
}
Use instruments to check for memory loss due to retained but not leaked memory. The latter is unused memory that is still pointed to. Use Heapshot in the Allocations instrument on Instruments.
For HowTo use Heapshot to find memory creap, see: bbum blog
Basically there method is to run Instruments allocate tool, take a heapshot, run an intuition of your code and another heapshot repeating 3 or 4 times. This will indicate memory that is allocated and not released during the iterations.
To figure out the results disclose to see the individual allocations.
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set "Record reference counts" on on (you have to stop recording to set the option). Cause the picker to run, stop recording, search for there ivar (datePickerView), drill down and you will be able to see where all retains, releases and autoreleases occurred.
Your code is not optimal. You should place all prepare methods before the loop.
if (sqlite3_open([dataPath UTF8String], &database) == SQLITE_OK) {
sqlite3_stmt *insertStmt = nil;
NSString *name = [song valueForProperty:MPMediaItemPropertyTitle];
if(insertStmt == nil) {
NSString *statement = [NSString stringWithFormat:#"INSERT INTO Songs (name) VALUES (?)"];
const char *insertSql = [statement UTF8String];
if(sqlite3_prepare_v2(database, insertSql, -1, &insertStmt, NULL) != SQLITE_OK){
NSLog(#"Error while creating insert statement.");
insertStmt = nil;
return;
}
}
for (int i = 0 ; i < count; i++) {
sqlite3_bind_text(insertStmt, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(insertStmt)){
NSLog(#"Error while inserting data.");
continue;
}
else{}
sqlite3_clear_bindings(insertStmt); //release bindings
sqlite3_reset(insertStmt);
[delegate IPodLibraryFinishEntity:self];
}
sqlite3_close(database);
}
Before starting each Insert statement use sqlite3_open and after execution of query put sqlite3_close statement. So that it wont make database object busy anymore after each Insert query execution.
I am trying get the data from my database but i am not getting solve out
I try like this
-(void)information
{
//[self createEditableCopyOfDatabaseIfNeeded];
NSString *filePath = [self getWritableDBPath];
sqlite3 *database;
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK)
{
NSString *qu = #"Select Name FROM empl where SyncStatus ='1'";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [qu UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK)
{
char *firstColumn = (char *)sqlite3_column_text(compiledStatement, 0);
if (firstColumn==nil)
{
NSString *name= [[NSString stringWithUTF8String:firstColumn]autorelease];
NSLog(#"%c",name);
}
if(sqlite3_step(compiledStatement) != SQLITE_ROW )
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"UIAlertView" message:#"User is not valid" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
alert = nil;
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
it get crash And
It show me error that reason: '* +[NSString stringWithUTF8String:]: NULL cString'
* Call stack at first throw:
use like this
if(sqlite3_step(compiledStatement) == SQLITE_ROW )
{
char *firstColumn = (char *)sqlite3_column_text(compiledStatement, 0);
NSString *name= [[NSString alloc]initWithUTF8String:firstColumn];
}
I hope it will help you try this
I think firstColumn is NULL , it make program crash . You try to check data in database is null.
This is actually obvious because you are trying to fetch data which is NULL
Try for this code for checking NULL in your code:
if (sqlite3_column_text(compiledStatement, 0)!= nil)
i.e.
if (sqlite3_column_text(compiledStatement, 0)!= nil)
char *firstColumn = (char *)sqlite3_column_text(compiledStatement, 0);
else
char *firstColumn = #"";
NSString *name= [[NSString stringWithUTF8String:firstColumn]autorelease];
NSLog(#"%c",name);
try this...
Hope it helps....
I think there are 2 issues with this piece of code.
As already pointed out you are checking for equal to nil and not for
different from nil.
To order of the sql functions should be:
sqlite3_open
sqlite3_prepare_v2
sqlite3_step
sqlite3_column_text
You can also read about this order of statements at:
http://www.iosdevelopment.be/sqlite-tutorial/
I have this simple function in my application :
-(NSMutableArray *)SelectProductID:(NSMutableArray *)arr
{
NSLog(#"----------------");
sqlite3_stmt *statement;
NSMutableArray *arrPordID = [[NSMutableArray alloc]init];
#try
{
//Get productID
for(NSString *strSubProductID in arr)
{
NSString *s = [NSString stringWithFormat:#"SELECT ProductID FROM SubProducttable where SubProductID=%#",strSubProductID];
const char *sql = [s cStringUsingEncoding:NSASCIIStringEncoding];
if (sqlite3_prepare_v2(database, [s cStringUsingEncoding:NSUTF8StringEncoding], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW){
char *dbString;
dbString = (char *)sqlite3_column_text(statement, 0);
NSString *pID = (dbString) ? [NSString stringWithUTF8String:dbString] : #"";
[arrPordID addObject:pID];
}
}
}
}
#catch (NSException *exception) {
#throw exception;
}
#finally {
sqlite3_finalize(statement);
}
return arrPordID;
}
I am encountering a strange problem here. When application reaches while (sqlite3_step(statement) == SQLITE_ROW){, loop is never entered. I don't know why. I executed the same query in SQLite manager (when application is not running). And I get result as a single one. The result I get is 2. But here I am getting nothing.
And yes, I always close the database in SQLite manager whenever I run my application. I have also cleaned the application, restarted XCode, and removed the application from simulator. But no success.
Also I saw a strange thing during debugging. While debugging, sqlite3_stmt *statement is always skipped. Is this the reason I am not getting any result?
Have you tried subproductId in single quotes?
NSString *s = [NSString stringWithFormat:#"SELECT ProductID FROM SubProducttable where SubProductID='%#'",strSubProductID];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlQuery = #"SELECT ProductID FROM SubProducttable where SubProductID=%#",strSubProductID;
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, statement, -1, &sqlQuery, NULL) == SQLITE_OK) {
while(sqlite3_step(sqlQuery ) == SQLITE_ROW) {
// Read the data and add to your array object
}
}
// Release the compiled statement from memory
sqlite3_finalize(statement);
}
sqlite3_close(database)
I have a massive problem with SQLite in my iPhone app, that needs to be fixed for a client soon! Basically i'm pulling a column from a database and loading it into a table view on viewWillAppear. It works fine, for the first few times the view is loaded but then suddenly it starts return empty (null) values. Upon inspection it appears that there is an issue with opening the database maybe but this is my first SQLite project so it's hard to figure out what's going on.
Here is the code I use to pull the SQL information:
+ (void) getInitialDataToDisplay:(NSString *)dbPath {
NSLog(#"INCOME CALLED 1");
NavTabAppDelegate *appDelegate = (NavTabAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.incomeArray = [[NSMutableArray alloc] init];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSLog(#"INCOME CALLED 2");
const char *sql = "select IncomeID, IncomeName from Income ORDER BY IncomeName asc";
//const char *sql2 = "select categoryID, Size from coffee";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
NSLog(#"INCOME CALLED 3");
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSLog(#"INCOME CALLED 4");
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
Income *incomeObj = [[Income alloc] initWithPrimaryKey:primaryKey];
//This is how I pull info from the database using the above select statement and setting it in the coffeeObj property of Coffee class
incomeObj.incomeName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
//coffeeObj.coffeeSize = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];
incomeObj.isDirty = NO;
[appDelegate.incomeArray addObject:incomeObj];
[incomeObj release];
NSLog(#"INCOME OBJECTS %#", incomeObj.incomeName);
//NSLog(#"CALLED");
}
}
}
else{
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory
NSLog(#"INCOME CALLED 5");
}
NSLog(#"INCOME CALLED 6");
}
I am calling the code in viewWillAppear as follows:
[Income getInitialDataToDisplay:[appDelegate getDBPath]];
Also this is the output from my console when the error occurs:
2011-06-17 12:21:48.307 CashCal[318:707] GET DB PATH CALLED
2011-06-17 12:21:48.310 CashCal[318:707] /var/mobile/Applications/2BD7CA1D-C7AB-4425-B5C1-974C4F4D057C/Documents/SQL.sqlite
2011-06-17 12:21:48.312 CashCal[318:707] INCOME CALLED 1
2011-06-17 12:21:48.314 CashCal[318:707] INCOME CALLED 5
2011-06-17 12:21:48.318 CashCal[318:707] INCOME CALLED 6
It appears the problem is with the first if statement opening the database. I really need help on this one
You should always destroy prepared statements by calling sqlite3_finalize(your_stmt). And you should always close youre connection not only if it sqlite3_open() failed.
Also do something like this:
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
//your code here
} else {
//print error
NSLog(#"sql-error: %s", sqlite3_errmsg(database));
}
for clarification, here a interface for your db, that should avoid opening the db when its allready open, and makes code cleaner
DBi.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#interface DBi : NSObject {
sqlite3* db;
}
- (void)opendDB;
- (void)closeDB;
- (NSArray*)getIcons;
#end
DBi.m
#import "DBi.h"
#import "Income.h"
static DBi *sharedDBi = nil;
#implementation DBi
- (void)dealloc {
sqlite3_close(db);
[super dealloc];
}
+ (DBi*)sharedManager {
if (sharedDBi == nil) {
sharedDBi = [[super allocWithZone:NULL] init];
[sharedDBi opendDB];
}
return sharedDBi;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedManager] retain];
}
- (void)opendDB {
NSString *dbPath = [[NSBundle mainBundle]pathForResource:#"path_to_db_file"ofType:#"sqlite"];
//open the database
if(!sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK) {
NSLog(#"connection to db failed");
sqlite3_close(db);
}
}
- (void)closeDB {
sqlite3_close(db);
}
- (NSArray*)getIncoms {
NSMutableArray rArray = [[[NSMutableArray alloc] init] autorelease];
const char *sql = "select IncomeID, IncomeName from Income ORDER BY IncomeName asc";
//const char *sql2 = "select categoryID, Size from coffee";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(db, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
Income *incomeObj = [[Income alloc] initWithPrimaryKey:primaryKey];
incomeObj.incomeName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
incomeObj.isDirty = NO;
[rArray addObject:incomeObj];
[incomeObj release];
}
} else {
NSLog(#"sql-error in getIncoms: %s", sqlite3_errmsg(db));
}
sqlite3_finalize(selectstmt);
return rArray;
}
Now you could do something like that.
DBi *dbi = [[DBi alloc] init];
NSArray *incoms = [dbi getIncoms];
[dbi release];
hope, that should help
use this code
sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
////your Code
if(sqlite3_prepare_v2(database, [sqlStatement cStringUsingEncoding:NSUTF8StringEncoding], -1, &compiledStatement, NULL) == SQLITE_OK)
{
NSLog(#"%#",sqlStatement);
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
//your code
}
}
sqlite3_finalize(compiledStatement);
sqlite3_close(database);
}
}
Use FMDB for you sqlite tasks. It's a bad practice to use sqlite calls everywhere in the application. Just search on google for FMDB Example you will find one. FMDB is much easier to implement then SQLIte because FMDB handles all the things.
It turns out I was calling the same SQL method in two different places in very quick succession before the statements had a chance to be finalised each time. I guess this caused some sort of overlap eventually leading to the statements becoming invalid. Thanks for all the help. I will definitely be using CoreData or FMDB next time.
I am using this in a method:
+ (void) getA:(NSString *)dbPath {
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
const char *sql = "select a from a_table";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
Coffee *coffeeObj = [[Coffee alloc] initWithPrimaryKey:primaryKey];
coffeeObj.aString = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt,0)];
coffeeObj.isDirty = NO;
[appDelegate.aArray addObject:coffeeObj.aString];
[coffeeObj release];
}
}
}
else
sqlite3_close(database);
}
When db has a row, it works fine, but when it has no rows, it just crashes.
What i need to know is, how can I handle my code so that it should work properly when there is no row in DB.
What should I add/modify in my code to behave properly, when there is no rows in the db?
Regards
I know this is a very old question but just had this problem of myself and put a very easy method to solve this. Hope this might help other visitors
In Your code
Coffee *coffeeObj = [[Coffee alloc] initWithPrimaryKey:primaryKey];
coffeeObj.aString = [self checkNullForSQLStatmentColoumn:sqlite3_column_text(selectstmt, 0)];
-(NSString *) checkNullForSQLStatmentColoumn : (const unsigned char *) coloumn{
if(coloumn)
{
return [NSString stringWithUTF8String:(const char *)coloumn];
}
return #"";
}
Try this: to check if something is not NSNull type
if((NSNull *)YourResource != [NSNull null])