I have a project needs to use the sqlite in it.
And I also create a singleton object to manage my sql
But I just found out that when I read data in sql,the memory just keep growing,and it seems never release.
the following code is how I read data in my singleton object
- (NSArray*)loadRecordPathData{
#synchronized(self)
{
if(sqlite3_open([FILEPATH UTF8String], &database) == SQLITE_OK)
{
NSMutableArray *pathNames = [[NSMutableArray alloc] init];
NSString *query = #"SELECT * FROM pathData";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil)
== SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
BBRecordPathData *recordPathData = [BBRecordPathData new];
int readed = (int) sqlite3_column_int(statement, 0);
int isFavorite = (int) sqlite3_column_int(statement, 1);
char *pathDescroption = (char *) sqlite3_column_text(statement, 2);
char *pathStopTime = (char *) sqlite3_column_text(statement, 3);
char *pathStartTime = (char *) sqlite3_column_text(statement, 4);
int pathChallange = (int) sqlite3_column_int(statement, 5);
char *pathName = (char *) sqlite3_column_text(statement, 6);
NSString *path_StartTime = (pathStartTime) ?[[NSString alloc] initWithUTF8String:pathStartTime] : nil;
NSString *path_StopTime = (pathStopTime) ? [[NSString alloc] initWithUTF8String:pathStopTime] : nil;
NSString *path_Name = (pathName) ? [[NSString alloc] initWithUTF8String:pathName]:nil;
NSString *path_description = (pathDescroption) ? [[NSString alloc] initWithUTF8String:pathDescroption]: nil;
recordPathData.recordPathName = path_Name;
recordPathData.recordPathStartTime = path_StartTime;
recordPathData.recordPathStopTime = path_StopTime;
recordPathData.recordPathDescription = path_description;
recordPathData.challange = pathChallange;
recordPathData.isFavorite = isFavorite;
recordPathData.readed = readed;
//get contain locations
recordPathData.cotainLocations = [self getLocationsPointFromStartTimeTag:recordPathData.recordPathStartTime]; //<----from another table
if (recordPathData.cotainLocations.count == 0 || recordPathData.cotainLocations.count < 4) {
recordPathData.distance = #"0.000KM";
}else{
NSString *unite = #"M";
float distanceInMeter = 0.0;
for (int i = 3; i < recordPathData.cotainLocations.count; i++) {
if (i <= recordPathData.cotainLocations.count - 2){
CLLocation *startPoint = recordPathData.cotainLocations[i];
CLLocation *endPoint = recordPathData.cotainLocations[i + 1];
distanceInMeter += [startPoint distanceFromLocation:endPoint];
}else{
recordPathData.distance = #"0.000KM";
}
}
if (distanceInMeter > 1000.0) {
unite = #"KM";
distanceInMeter /= 1000.0;
recordPathData.distance = [NSString stringWithFormat:#"%.2f%#",distanceInMeter,unite];
}else{
recordPathData.distance = [NSString stringWithFormat:#"%i%#",(int)distanceInMeter,unite];
}
}
[pathNames addObject:recordPathData];
}
sqlite3_finalize(statement);
sqlite3_close(database);
}
return pathNames;
}
return nil;
}
}
any suggestion or advice will be a great help , thanks!
If you're using SQLite from Objective C, you should use a wrapper, such as FMDatabase. It will handle the memory management for you and ensure you don't leak.
Related
Here is the code that using SQLite.
This function will be call from some threads.
I don't know well, following code is correct one or not.
There are lock/unlock code.
Please advice me whether I used lock/unlock correctly.
- (NSMutableArray*) Query:(NSString *)query_str forColumn:(NSString*)mycolumn
{
sqlite3_stmt *statement;
const char *query_stmt = [query_str UTF8String];
[dbLock lock];
if (sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL) != SQLITE_OK) {
[dbLock unlock];
return nil;
}
NSMutableArray *queryResult = [NSMutableArray array];
while (sqlite3_step(statement) == SQLITE_ROW) {
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
int num_of_fields = sqlite3_column_count(statement);
for (int i = 0; i < num_of_fields; i++) {
NSString * col_name = [[NSString alloc] initWithUTF8String:sqlite3_column_name(statement, i)];
const char * value = (const char *)sqlite3_column_text(statement, i);
NSString * col_text;
if (value)
col_text = [[NSString alloc] initWithUTF8String:value];
else
col_text = #"";
if (col_name && col_text) {
if ([col_text isEqualToString:#"--"] == NO && [col_text isEqualToString:#""] == NO)
[dict setObject:col_text forKey:col_name];
}
}
if (mycolumn == nil) {
[queryResult addObject:dict];
} else {
NSString *tmp = [dict objectForKey:mycolumn];
if (tmp != nil) {
[queryResult addObject:tmp];
}
}
}
sqlite3_finalize(statement);
[dbLock unlock];
return queryResult;
}
The locking is around all the database access functions, so as long as all the other database access code also does similar locking, the database is protected.
The query_str access is outside the lock, so it is not protected against concurrent modifications. Whether that could happen in your program is something only you can decide.
I feel I am missing the obvious, the code below pulls back three results "201501, 201502 & 201503" I would like to put each result in its own UITextfield, I could have unto 52 results, can anyone help with the missing code, many thanks
_startWeekText.text = 201501
_endWeekText.text = 201503
- (void)allResults{
const char *dbpath_rm1 = [databasePath UTF8String];
sqlite3_stmt *statementrm1;
if (sqlite3_open(dbpath_rm1, &dataTV) == SQLITE_OK) {NSLog(#"Select db opened");
NSString *querySQLPrm1 = [NSString stringWithFormat:
#"SELECT Wk_Num FROM trendViewData WHERE (Name =\"%#\" ) AND (Wk_Num >= \"%#\" AND Wk_Num <= \"%#\") ",_resultSearchText.text,_startWeekText.text,_endWeekText.text];
const char *query_stmtrm = [querySQLPrm1 UTF8String];
if (sqlite3_prepare_v2(dataTV,
query_stmtrm, -1, &statementrm1, NULL) == SQLITE_OK)
while (sqlite3_step(statementrm1) == SQLITE_ROW) {
NSString *rm1 = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statementrm1, 0)];
_wk1.text = rm1;
NSString *rm2 = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statementrm1, 0)];
_wk2.text = rm2;
NSString *rm3 = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statementrm1, 0)];
_wk3.text = rm3;
}
sqlite3_finalize(statementrm1); }
sqlite3_close(dataTV);NSLog(#"Select db Closed");
NSLog(#"%#",_wk);
}
You could have an array of your UITextField references, and then populate it on the basis of that:
NSArray *fields = #[_wk1, _wk2, _wk3];
NSInteger index = 0;
const char *dbpath_rm1 = [databasePath UTF8String];
sqlite3_stmt *statementrm1;
if (sqlite3_open(dbpath_rm1, &dataTV) == SQLITE_OK) {
NSLog(#"Select db opened");
const char *query_stmtrm = "SELECT Wk_Num FROM trendViewData WHERE (Name = ?) AND (Wk_Num >= ? AND Wk_Num <= ?)";
if (sqlite3_prepare_v2(dataTV, query_stmtrm, -1, &statementrm1, NULL) == SQLITE_OK) {
if (sqlite3_bind_text(statementrm1, 1, [_resultSearchText.text UTF8String], -1, NULL) != SQLITE_OK) {
NSLog(#"Bind 1 failed");
}
if (sqlite3_bind_text(statementrm1, 2, [_startWeekText.text UTF8String], -1, NULL) != SQLITE_OK) {
NSLog(#"Bind 2 failed");
}
if (sqlite3_bind_text(statementrm1, 3, [_endWeekText.text UTF8String], -1, NULL) != SQLITE_OK) {
NSLog(#"Bind 3 failed");
}
while (sqlite3_step(statementrm1) == SQLITE_ROW) {
if (index < [fields count]) {
UITextField *field = fields[index];
NSString *rm = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statementrm1, 0)];
field.text = rm;
index++;
} else {
NSLog(#"Got more results than I was expecting!");
}
}
sqlite3_finalize(statementrm1);
} else {
NSLog(#"prepare failed: %s", sqlite3_errmsg(dataTV));
}
sqlite3_close(dataTV);NSLog(#"Select db Closed");
} else {
NSLog(#"open failed");
}
Also, note, I log messages if any of the SQLite calls fail and I don't use stringWithFormat to build the SQL, but rather I use sqlite_bind_text.
I have a table in a database which I access like this:
+(NSMutableArray *) queryDatabaseWithSQL:(NSString *)sql params:(NSArray *)params {
sqlite3 *database;
NSMutableArray *rtn = [[NSMutableArray alloc] init];
int index = 0;
NSString *filepath = [self copyDatabaseToDocumentsWithName:#"database"];
if (sqlite3_open([filepath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = [sql cStringUsingEncoding:NSASCIIStringEncoding];
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
if ([params count]) {
for (int i = 0; i < [params count]; i++) {
NSString *obj = [params objectAtIndex:i];
sqlite3_bind_blob(compiledStatement, i + 1, [obj UTF8String], -1, SQLITE_TRANSIENT);
}
}
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSMutableArray *arr = [[NSMutableArray alloc] init];
index = 0;
const char *s = (char *)sqlite3_column_text(compiledStatement, index);
while (s) {
[arr addObject:[NSString stringWithUTF8String:s]];
index++;
s = (char *)sqlite3_column_text(compiledStatement, index);
}
if (![rtn containsObject:arr]) {
[rtn addObject:arr];
}
}
}
sqlite3_finalize(compiledStatement);
}
NSLog(#"ERROR: %s", sqlite3_errmsg(database));
sqlite3_close(database);
return rtn;
}
This works fine when I call the function like this:
NSLog(#"%#", [database queryDatabaseWithSQL:#"SELECT * FROM FRIENDSUSERS WHERE USER = ?" params:#[[delegate->user objectForKey:#"username"]]]);
Then when I call the function using a string like this it doesn't return any rows:
NSLog(#"%#", [database queryDatabaseWithSQL:#"SELECT * FROM FRIENDSUSERS WHERE USER = ?" params:#[#"username"]]);
I haven't got a clue what is going one with but I have checked the strings match and they do so I'm now stuck
Can anyone see any reason why this would not work
I have run error checks as well and every time it returns no error, or rows :(
Thanks in advance
So I get this error: Prepare failure 'out of memory.' Does anyone know why this would be? Note I tested my sql statement. It works great. Also, I am checking to open the database inside another method. It opens just fine. Any help would be appreciated. Thanks!
+(NSArray *) fetchListForFirstLEvelCategory
{
NSMutableArray * array = [[NSMutableArray alloc]init];
NSString * query;
query = [NSString stringWithFormat:#"select mobile_menu.title from sup_pick join sup_mast as mobile_menu on mobile_menu.custom_link1 = sup_pick.key_id and mobile_menu.show_id = '1D2EA159-A312-4FB5-8FE5-B95879B242BB' and mobile_menu.type = 996 and mobile_menu.active = 1 and mobile_menu.status = 1 where sup_pick.client_id = '2517EFF6-8063-4454-BA5F-23679F51AD5A' and sup_pick.active = 1 and sup_pick.parent_key = 'CB18E277-23E9-4232-A20C-AD4D051C578B' and sup_pick.field_name like '%%0000' Order by sup_pick.field_name,mobile_menu.display_order"];
const char *query_stmt = [query UTF8String];
sqlite3_stmt * sql;
if (sqlite3_prepare_v2(db, query_stmt, -1, &sql, NULL) == SQLITE_OK)
{
while (sqlite3_step(sql)==SQLITE_ROW)
{
NSString* test= [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 0)];
[array addObject:test];
}
return array;
}
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
return nil;
}
+(NSArray *) fetchListForFirstLEvelCategory
{
NSMutableArray * array = [[NSMutableArray alloc]init];
NSString * query;
query = [NSString stringWithFormat:#"select mobile_menu.title from sup_pick join sup_mast as mobile_menu on mobile_menu.custom_link1 = sup_pick.key_id and mobile_menu.show_id = '1D2EA159-A312-4FB5-8FE5-B95879B242BB' and mobile_menu.type = 996 and mobile_menu.active = 1 and mobile_menu.status = 1 where sup_pick.client_id = '2517EFF6-8063-4454-BA5F-23679F51AD5A' and sup_pick.active = 1 and sup_pick.parent_key = 'CB18E277-23E9-4232-A20C-AD4D051C578B' and sup_pick.field_name like '%%0000' Order by sup_pick.field_name,mobile_menu.display_order"];
const char *query_stmt = [query UTF8String];
sqlite3_stmt * sql;
if (sqlite3_prepare_v2(db, query_stmt, -1, &sql, NULL) == SQLITE_OK)
{
while (sqlite3_step(sql)==SQLITE_ROW)
{
NSString* test= [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 0)];
[array addObject:test];
}
return array;
}
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
return nil;
}
I might be doing this all wrong as I am still new to Objective C.
I am trying to retrieve data from an sqlite3 database and store it in a NSObject array.
Here is the viewDidLoad method in my implementation file.
- (void)viewDidLoad
{
[super viewDidLoad];
clients = [[NSMutableArray alloc] init];
[self openDB];
NSString *sql = [NSString stringWithFormat:#"SELECT * FROM clients"];
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil)==SQLITE_OK)
{
while (sqlite3_step(statement)==SQLITE_ROW) {
char *field1 = (char *) sqlite3_column_text(statement, 0);
NSString *field1Str = [[NSString alloc]initWithUTF8String:field1];
char *field2 = (char *) sqlite3_column_text(statement, 1);
NSString *field2Str = [[NSString alloc]initWithUTF8String:field2];
char *field3 = (char *) sqlite3_column_text(statement, 2);
NSString *field3Str = [[NSString alloc]initWithUTF8String:field3];
char *field4 = (char *) sqlite3_column_text(statement, 3);
NSString *field4Str = [[NSString alloc]initWithUTF8String:field4];
char *field5 = (char *) sqlite3_column_text(statement, 4);
NSString *field5Str = [[NSString alloc]initWithUTF8String:field5];
char *field6 = (char *) sqlite3_column_text(statement, 5);
NSString *field6Str = [[NSString alloc]initWithUTF8String:field6];
char *field7 = (char *) sqlite3_column_text(statement, 6);
NSString *field7Str = [[NSString alloc]initWithUTF8String:field7];
char *field8 = (char *) sqlite3_column_text(statement, 7);
NSString *field8Str = [[NSString alloc]initWithUTF8String:field8];
char *field9 = (char *) sqlite3_column_text(statement, 8);
NSString *field9Str = [[NSString alloc]initWithUTF8String:field9];
ClientObj *c1 = [[ClientObj alloc] initWithCompanyName:field1Str firstName:field2Str lastName:field3Str email:field4Str workPhone:field5Str mobilePhone:field6Str streetAddress:field7Str city:field8Str postalCode:field9Str];
}
}
self.clients = [NSArray arrayWithObjects:c1,c2,c3,c4, nil];
}
I am trying to increment *c1 each time the while statement loops through the database. eg. c1, c2 ,c3, c4
I am then trying to add each ClientObj created from the database loop above to the clients array but I am not sure how to do this.
Any help or advice is very much appreciated
Initialize the array once before the loop:
self.clients = [[NSMutableArray alloc] init];
and then just add each client object to the array inside the loop:
while (sqlite3_step(statement) == SQLITE_ROW) {
// ...
ClientObj *c = [[ClientObj alloc] initWithCompanyName:field1Str firstName:field2Str lastName:field3Str email:field4Str workPhone:field5Str mobilePhone:field6Str streetAddress:field7Str city:field8Str postalCode:field9Str];
[self.clients addObject:c];
}