I am new to iOS. I am trying to implement a SQLite database.
My problem is that when I go to fetch data from database, it takes a lot of time even though there are only 50 records inside the tables.
I did make a separate method for fetching data because many times I need to retrieve data for different tables.
My method:
-(NSArray*)fetch_data:(NSString *)table_name fields_arr:(NSMutableArray *)fields_arr{
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = dirPaths[0];
databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent: #"test.db"]];
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
sqlite3_stmt *SelectStatement;
NSMutableDictionary *record_dict;
NSString *SelectQry=#"select ";
NSString *lastField = [fields_arr lastObject];
for (int i =0; i<[fields_arr count]; i++) {
if (fields_arr[i] == lastField) {
SelectQry = [SelectQry stringByAppendingString:[NSString stringWithFormat:#"%# ",fields_arr[i]]];
} else {
SelectQry = [SelectQry stringByAppendingString:[NSString stringWithFormat:#"%#,",fields_arr[i]]];
}
}
SelectQry = [SelectQry stringByAppendingString:[NSString stringWithFormat:#"from %#",table_name]];
const char *query_stmt = [SelectQry UTF8String];
NSMutableArray *resultArray = [[NSMutableArray alloc]init];
if (sqlite3_prepare_v2(database,
query_stmt, -1, &SelectStatement, NULL) == SQLITE_OK)
{
while(sqlite3_step(SelectStatement) == SQLITE_ROW)
{
record_dict=[[NSMutableDictionary alloc]init];
for (int i = 0; i<[fields_arr count]; i++) {
NSString *field_value = [[NSString alloc]init];
field_value = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(SelectStatement, i)];
[record_dict setValue:field_value forKey:fields_arr[i]];
}
[resultArray addObject:record_dict];
}
return resultArray;
//sqlite3_reset(statement);
sqlite3_finalize(SelectStatement);
}
else{
sqlite3_finalize(SelectStatement);
return nil;
}
}
In your code you are opening database connection for each time method is called for fetching data. This is not appropriate way. You must establish connection only once and use it.
+(sqlite3 *)openDatabase{
if (database == NULL) {
NSString* str_path=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [str_path stringByAppendingPathComponent:strDatabaseName];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
NSLog(#"Database Successfully Opened");
}
else {
NSLog(#"Error in opening database");
database = NULL;
}
}
return database;}
You can call this on app launch from app delegate and define this method in a class where you are defining other DB methods. I hope it will reduce some overhead and will reduce some time too.
Related
This question already has answers here:
sqlite error database is locked
(8 answers)
Closed 6 years ago.
I am getting error Database Locked.
at first attempt it adds the row but after that i am getting the error
database locked.
I am trying to make web page saver so at first time when app loads it is adding the row but when again I try to save any webpage it is not saving and I am getting the error database locked.
Even the deletion is also not happening after saving one web page.
#import "DBManager.h"
static DBManager *sharedInstance = nil;
static sqlite3 *database = nil;
static sqlite3_stmt *statement = nil;
#implementation DBManager
+(DBManager*)getSharedInstance{
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL]init];
[sharedInstance createDB];
}
return sharedInstance;
}
-(BOOL)createDB{
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent: #"browser.db"]];
BOOL isSuccess = YES;
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
char *errMsg;
NSLog(#"insod");
const char *sql_stmt ="create table if not exists list(sno int primary key,name varchar(50),category varchar(30),path varchar(500),fav int)";
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg)
!= SQLITE_OK)
{
isSuccess = NO;
NSLog(#"Failed to create table");
}
sqlite3_close(database);
return isSuccess;
}
else {
isSuccess = NO;
NSLog(#"Failed to open/create database");
}
}else{
NSLog(#"File Exist");
}
return isSuccess;
}
-(BOOL) Delete:(NSString *) name{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK){
NSString *query = [NSString stringWithFormat:#"delete from list where name like '%#'",name];
const char *stmt = [query UTF8String];
sqlite3_prepare_v2(database, stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
NSLog(#"error: %s",sqlite3_errmsg(database));
sqlite3_finalize(statement);
return NO;
}
}else{
sqlite3_close(database);
return NO;
}
}
-(NSDictionary *) CatList:(NSString *) cat{
const char *dbpath = [databasePath UTF8String];
NSDictionary *dict;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL =[NSString stringWithFormat:#"select name,path from list where category like '%#'",cat];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
// NSLog(#"inside list");
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
NSMutableArray *arr2 = [[NSMutableArray alloc] init];
// NSMutableArray *arr3 = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSString *name = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
[arr1 addObject:name];
//NSLog(#"%#",name);
NSString *category = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
[arr2 addObject:category];
// //NSLog(#"%#",dept);
// NSString *path = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 3)];
// [arr3 addObject:path];
}
sqlite3_finalize(statement);
dict = #{#"name":arr1,#"path":arr2};
//NSLog(#"%#",dict);
}else{
NSLog(#"error: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
return dict;
}
- (BOOL) saveData:(NSString*)name category:(NSString*)category path:(NSString*)path{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *highest = #"select max(sno) from list";
const char *Query = [highest UTF8String];
if (sqlite3_prepare_v2(database, Query, -1, &statement, NULL) == SQLITE_OK){
if (sqlite3_step(statement) == SQLITE_ROW){
int sno = sqlite3_column_int(statement, 0);
NSString *insertSQL = [NSString stringWithFormat:#"insert into list values(\"%d\",\"%#\",\"%#\", \"%#\",\"%d\")",sno+1,name, category, path,0];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
sqlite3_finalize(statement);
return NO;
}
}else{
NSString *insertSQL = [NSString stringWithFormat:#"insert into list values(\"%d\",\"%#\",\"%#\", \"%#\",\"%d\")",1,name, category, path,0];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
sqlite3_finalize(statement);
return NO;
}
}
}
sqlite3_close(database);
}
return NO;
}
-(BOOL) Fav:(NSString *) name{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK){
NSString *query = [NSString stringWithFormat:#"update list set fav = 1 where name like '%#'",name];
const char *stmt = [query UTF8String];
sqlite3_prepare_v2(database, stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
sqlite3_finalize(statement);
return NO;
}
}else{
return NO;
}
}
-(NSArray *) GetListFav{
const char *dbpath = [databasePath UTF8String];
NSArray *dict;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = #"select name from list where fav = 1";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSString *name = [[NSString alloc] initWithUTF8String: (const char *) sqlite3_column_text(statement, 0)];
[arr1 addObject:name];
}
sqlite3_finalize(statement);
dict = arr1;
}else{
NSLog(#"error: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
return dict;
}
-(BOOL) removeFav:(NSString *) name{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK){
NSString *query = [NSString stringWithFormat:#"update list set fav = 0 where name like '%#'",name];
const char *stmt = [query UTF8String];
sqlite3_prepare_v2(database, stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
sqlite3_finalize(statement);
return NO;
}
}else{
return NO;
}
}
-(NSArray *) GetList{
const char *dbpath = [databasePath UTF8String];
NSArray *dict;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = #"select name from list";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
//NSLog(#"inside list");
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSString *name = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
[arr1 addObject:name];
}
sqlite3_finalize(statement);
dict = arr1;
}else{
NSLog(#"error: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
return dict;
}
#end
You can only access sqllite once at a time. If you have multiple threads, you can run in this situation. Example:
So always try to close database once it is used using:
sqlite3_close(database);
You need to make sure every sqlite3_open is balanced with a sqlite3_close before trying to do sqlite3_open again:
Your saveData method has quite a few return statements that will prevent the database from ever calling sqlite3_close. Make sure all paths out of the method close the database properly. In the end, this means that you'll try to open the database although it's already open.
Or, better, just open the database once and leave it open, eliminating the repeated opening and closing of the database.
Your Delete, Fav, and removeFav methods are also not closing the database.
A few unrelated observations:
You should be wary about using stringWithFormat to build SQL with string parameters. If the string being searched for had a apostrophe in it, your code will fail. Use ? placeholders and then use sqlite3_bind_text to bind values to those placeholders.
If you make your sno column a AUTOINCREMENT, you won't have to do that "get the max sno before inserting new row" logic. Thus, the CREATE statement might look like:
create table if not exists list (
sno integer primary key autoincrement,
name text,
category text,
path text,
fav integer)
You can then omit sno from the INSERT statements, and it will automatically be assigned a unique identifier.
I have created multiple tables in my database. And now I want insert data into those tables. How to insert multiple tables data can anyone help regarding this.
I have written this code for creating 1 table:
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO ATRG (id, name, language,imgurl) VALUES ( \"%#\",\"%#\",\"%#\",\"%#\")", ID, name, lang,imgUrl];
const char *insert_stmt = [insertSQL UTF8String]; sqlite3_prepare_v2(_globalDataBase, insert_stmt, -1, &statement, NULL); if (sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#"Record Inserted");
} else { NSLog(#"Failed to Insert Record");
}
Try this I hope it would be helpful!! This is mine code for insert data
#import "Sqlitedatabase.h"
#implementation Sqlitedatabase
+(NSString* )getDatabasePath
{
NSString *docsDir;
NSArray *dirPaths;
sqlite3 *DB;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
NSString *databasePath = [docsDir stringByAppendingPathComponent:#"myUser.db"];
NSFileManager *filemgr = [[NSFileManager alloc]init];
if ([filemgr fileExistsAtPath:databasePath]==NO) {
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath,&DB)==SQLITE_OK) {
char *errorMessage;
const char *sql_statement = "CREATE TABLE IF NOT EXISTS users(ID INTEGER PRIMARY KEY AUTOINCREMENT,FIRSTNAME TEXT,LASTNAME TEXT,EMAILID TEXT,PASSWORD TEXT,BIRTHDATE DATE)";
if (sqlite3_exec(DB,sql_statement,NULL,NULL,&errorMessage)!=SQLITE_OK) {
NSLog(#"Failed to create the table");
}
sqlite3_close(DB);
}
else{
NSLog(#"Failded to open/create the table");
}
}
NSLog(#"database path=%#",databasePath);
return databasePath;
}
+(NSString*)encodedString:(const unsigned char *)ch
{
NSString *retStr;
if(ch == nil)
retStr = #"";
else
retStr = [NSString stringWithCString:(char*)ch encoding:NSUTF8StringEncoding];
return retStr;
}
+(BOOL)executeScalarQuery:(NSString*)str{
NSLog(#"executeScalarQuery is called =%#",str);
sqlite3_stmt *statement= nil;
sqlite3 *database;
BOOL fRet = NO;
NSString *strPath = [self getDatabasePath];
if (sqlite3_open([strPath UTF8String],&database) == SQLITE_OK) {
if (sqlite3_prepare_v2(database, [str UTF8String], -1, &statement, NULL) == SQLITE_OK) {
if (sqlite3_step(statement) == SQLITE_DONE)
fRet =YES;
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
return fRet;
}
+(NSMutableArray *)executeQuery:(NSString*)str{
sqlite3_stmt *statement= nil; // fetch data from table
sqlite3 *database;
NSString *strPath = [self getDatabasePath];
NSMutableArray *allDataArray = [[NSMutableArray alloc] init];
if (sqlite3_open([strPath UTF8String],&database) == SQLITE_OK) {
if (sqlite3_prepare_v2(database, [str UTF8String], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSInteger i = 0;
NSInteger iColumnCount = sqlite3_column_count(statement);
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
while (i< iColumnCount) {
NSString *str = [self encodedString:(const unsigned char*)sqlite3_column_text(statement, (int)i)];
NSString *strFieldName = [self encodedString:(const unsigned char*)sqlite3_column_name(statement, (int)i)];
[dict setObject:str forKey:strFieldName];
i++;
}
[allDataArray addObject:dict];
}
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
return allDataArray;
}
#end
And called that method where you want to use!!
NSString *insertSql = [NSString stringWithFormat:#"INSERT INTO users(firstname,lastname,emailid,password,birthdate) VALUES ('%#','%#','%#','%#','%#')",_firstNameTextField.text,_lastNameTextField.text,_emailTextField.text,_passwordTextField.text,_BirthdayTextField.text];
if ([Sqlitedatabase executeScalarQuery:insertSql]==YES)
{
[self showUIalertWithMessage:#"Registration succesfully created"];
}else{
NSLog(#"Data not inserted successfully");
}
And If you want to fetch data from table then you can do this!!
NSString *insertSql = [NSString stringWithFormat:#"select emailid,password from users where emailid ='%#' and password = '%#'",[_usernameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]],[_passwordTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
NSMutableArray *data =[Sqlitedatabase executeQuery:insertSql];
NSLog(#"Fetch data from database is=%#",data);
Multiple Execute Query!!
NSString *insertSql = [NSString stringWithFormat:#"INSERT INTO users (firstname,lastname,emailid,password,birthdate) VALUES ('%#','%#','%#','%#','%#')",_firstNameTextField.text,_lastNameTextField.text,_emailTextField.text,_passwordTextField.text,_BirthdayTextField.text];
NSString *insertSql1 = [NSString stringWithFormat:#"INSERT INTO contact (firstname,lastname,emailid,password,birthdate) VALUES ('%#','%#','%#','%#','%#')",_firstNameTextField.text,_lastNameTextField.text,_emailTextField.text,_passwordTextField.text,_BirthdayTextField.text];
NSMutableArray * array = [[NSMutableArray alloc]initWithObjects:insertSql,insertSql1,nil];
for (int i=0; i<array.count; i++)
{
[Sqlitedatabase executeScalarQuery:[array objectAtIndex:i]];
}
See this for your issue:
Insert multiple tables in same database in sqlite
or if you want
Multi-table INSERT using one SQL statement in AIR SQLite
then use this:
http://probertson.com/articles/2009/11/30/multi-table-insert-one-statement-air-sqlite/
I have an sqlite file in my documents folder (I cheched and it's there). The issue is that the function openDatabase always prints Yes, even if I give it wrong path, so this is wierd.
The second thing is
if (sqlite3_prepare_v2(localDB,query_stmt, -1, &statement, NULL) == SQLITE_OK)
it always goes to else and print "Error on SQLITE_OK". Can you please help me with my code:
#interface SQLReader ()
{
sqlite3 *localDB;
}
#end
#implementation SQLReader
- (void)viewDidLoad {
[super viewDidLoad];
[self openDatabase];
sqlite3_stmt *statement;
NSString *querySQL = #"SELECT * FROM Animations";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(localDB,query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *addressField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
NSString *phoneField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
NSLog(#"%#",addressField);
NSLog(#"%#",phoneField);
}
else
{
NSLog(#"%s","Match not found");
}
sqlite3_finalize(statement);
}
else
{
NSLog(#"%s","Error on SQLITE_OK");
}
}
- (void)openDatabase
{
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
char *dbpath = (char *)[[documentsPath stringByAppendingPathComponent: #"Bemad/IR_World/DB/IRRMobile.sqlite"] UTF8String];
BOOL openDatabaseResult = sqlite3_open(dbpath, &localDB);
NSLog(openDatabaseResult ? #"DB: Yes" : #"DB: No");
}
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
I'm working on an app that displays various feeds using ASIHTTPRequest. The user can add new sources to the app that are stored in an SQLite database. Currently I give the feeds to the app in the viewDidLoad method of my FeedsViewController but i want to be able to retrieve the data that contains the link for the source and store it in an array to use it.
Currently the app looks like and below the current code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.title =#"Lajmet";
self.navigationController.navigationBar.tintColor = [UIColor blackColor];
//self.tabBarController.tabBar.tintColor = [UIColor blackColor];
self.allEntries = [NSMutableArray array];
self.queue = [[NSOperationQueue alloc] init];
self.feeds = [NSMutableArray arrayWithObjects:#"http://pcworld.al/feed",#"http://geek.com/feed", #"http://feeds.feedburner.com/Mobilecrunch",#"http://zeri.info/rss/rss-5.xml",
nil];
[self.tableView reloadData];
[self refresh];
}
My view that contains the function (AddSourcesViewController) to add and delete new sources looks like this and here the code:
- (void)viewDidLoad
{
[super viewDidLoad];
arrayOfSource = [[NSMutableArray alloc]init];
[[self myTableView]setDelegate:self];
[[self myTableView]setDataSource:self];
[self createOrOpenDB];
// Display sources in table view
sqlite3_stmt *statement;
if (sqlite3_open([dbPathString UTF8String], &sourceDB)==SQLITE_OK) {
[arrayOfSource removeAllObjects];
NSString *querySql = [NSString stringWithFormat:#"SELECT * FROM SOURCES"];
const char* query_sql = [querySql UTF8String];
if (sqlite3_prepare(sourceDB, query_sql, -1, &statement, NULL)==SQLITE_OK) {
while (sqlite3_step(statement)==SQLITE_ROW) {
NSString *name = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 1)];
NSString *link = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 2)];
NSString *category = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 3)];
SourceDB *source = [[SourceDB alloc]init];
[source setName:name];
[source setLink:link];
[source setCategory:category];
[arrayOfSource addObject:source];
}
}
}
[[self myTableView]reloadData];
}
- (void)createOrOpenDB
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [path objectAtIndex:0];
dbPathString = [docPath stringByAppendingPathComponent:#"sources.db"];
char *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:dbPathString]) {
const char *dbPath = [dbPathString UTF8String];
//creat db here
if (sqlite3_open(dbPath, &sourceDB)==SQLITE_OK) {
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS SOURCES (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, LINK TEXT, CATEGORY TEXT)";
sqlite3_exec(sourceDB, sql_stmt, NULL, NULL, &error);
sqlite3_close(sourceDB);
}
}
}
- (IBAction)addSourceButton:(id)sender
{
char *error;
if (sqlite3_open([dbPathString UTF8String], &sourceDB)==SQLITE_OK) {
NSString *inserStmt = [NSString stringWithFormat:#"INSERT INTO SOURCES(NAME,LINK,CATEGORY) values ('%s', '%s','%s')",[self.nameField.text UTF8String], [self.linkField.text UTF8String],[self.categoryField.text UTF8String]];
const char *insert_stmt = [inserStmt UTF8String];
if (sqlite3_exec(sourceDB, insert_stmt, NULL, NULL, &error)==SQLITE_OK) {
NSLog(#"Source added");
SourceDB *source = [[SourceDB alloc]init];
[source setName:self.nameField.text];
[source setLink:self.linkField.text];
[source setCategory:self.categoryField.text];
[arrayOfSource addObject:source];
}
sqlite3_close(sourceDB);
}
}
- (IBAction)deleteSourceButton:(id)sender
{
[[self myTableView]setEditing:!self.myTableView.editing animated:YES];
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
SourceDB *s = [arrayOfSource objectAtIndex:indexPath.row];
[self deleteData:[NSString stringWithFormat:#"Delete from sources where name is '%s'", [s.name UTF8String]]];
[arrayOfSource removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
-(void)deleteData:(NSString *)deleteQuery
{
char *error;
if (sqlite3_exec(sourceDB, [deleteQuery UTF8String], NULL, NULL, &error)==SQLITE_OK) {
NSLog(#"Source deleted");
}
}
- (IBAction)showSourceButton:(id)sender
{
sqlite3_stmt *statement;
if (sqlite3_open([dbPathString UTF8String], &sourceDB)==SQLITE_OK) {
[arrayOfSource removeAllObjects];
NSString *querySql = [NSString stringWithFormat:#"SELECT * FROM SOURCES"];
const char* query_sql = [querySql UTF8String];
if (sqlite3_prepare(sourceDB, query_sql, -1, &statement, NULL)==SQLITE_OK) {
while (sqlite3_step(statement)==SQLITE_ROW) {
NSString *name = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 1)];
NSString *link = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 2)];
NSString *category = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 3)];
SourceDB *source = [[SourceDB alloc]init];
[source setName:name];
[source setLink:link];
[source setCategory:category];
[arrayOfSource addObject:source];
}
}
}
[[self myTableView]reloadData];
}
Now i created a method in my FeedsViewConrtoller:
-(void)ReadData
{
[self createOrOpenDB];
feedsArray = [[NSMutableArray alloc] init];
const char *dbPath = [dbPathString UTF8String];
if (sqlite3_open(dbPath, &sourceDB)==SQLITE_OK)
{
const char *sqlstmt = "SELECT LINK FROM SOURCES";
sqlite3_stmt *completedstmt;
if (sqlite3_prepare_v2(sourceDB, sqlstmt, -1, &completedstmt, NULL)==SQLITE_OK)
{
while(sqlite3_step(completedstmt)==SQLITE_ROW)
{
NSString *link = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(completedstmt, 2)];
SourceDB *source = [[SourceDB alloc]init];
[source setLink:link];
[feedsArray addObject:link];
}
}
}
}
And when i change
self.feeds = [NSMutableArray arrayWithObjects:#"http://pcworld.al/feed",#"http://geek.com/feed", #"http://feeds.feedburner.com/Mobilecrunch",#"http://zeri.info/rss/rss-5.xml",
nil];
to:
self.feeds = [NSMutableArray arrayWithArray:feedsArray];
i get the following error:
2013-08-14 15:03:55.328 ShqipCom[3128:c07] (null)
What am i doing wrong here?
Thanks a lot!
Granit
In ReadData, you're returning one column, but then retrieving the third column with:
NSString *link = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(completedstmt, 2)];
That should be:
NSString *link = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(completedstmt, 0)];
A couple of other thoughts:
Part of the reason it's hard for us to answer this is that you aren't reporting SQLite errors. I'd suggest logging when a SQLite test failed, e.g.:
if (sqlite3_prepare_v2(sourceDB, sqlstmt, -1, &completedstmt, NULL)==SQLITE_OK
{
while(sqlite3_step(completedstmt)==SQLITE_ROW)
{
NSString *link = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(completedstmt, 2)];
SourceDB *source = [[SourceDB alloc]init];
[source setLink:link];
[feedsArray addObject:link];
}
}
whereas you might want something like:
if (sqlite3_prepare_v2(sourceDB, sqlstmt, -1, &completedstmt, NULL)!=SQLITE_OK
{
NSLog(#"%s: prepare error: %s", __FUNCTION__, sqlite3_errmsg(sourceDB));
return;
}
int rc;
while ((rc = sqlite3_step(completedstmt)) == SQLITE_ROW)
{
NSString *link = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(completedstmt, 2)];
SourceDB *source = [[SourceDB alloc]init];
[source setLink:link];
[feedsArray addObject:link];
}
if (rc != SQLITE_DONE)
{
NSLog(#"%s: step error: %s", __FUNCTION__, sqlite3_errmsg(sourceDB));
return;
}
You really should be checking the result of every SQLite call, and reporting an error message if not successful. Otherwise you're flying blind.
On your INSERT statement, are you 100% sure that those three fields will never have an apostrophe in them? (Also, if the user is entering any of this data, you have to be concerned about SQL injection attacks.) Generally you'd use ? placeholders in your SQL, you'd prepare the SQL with sqlite3_prepare_v2, and then use sqlite3_bind_text to bind text values to those placeholders, and then you'd sqlite3_step and confirm a return value of SQLITE_DONE.
Note, checking each and every sqlite3_xxx function call return result and doing all of the necessary sqlite3_bind_xxx calls is a little cumbersome. In your next project, if you want to streamline your SQLite code, you might want to consider using FMDB.
Your can add any object in NSMutableArray by
[myArray name addObject:mYString]; // add whatever object here;
if you want to add Array to you NSMutableArray
[myArray addObjectsFromArray:anOtherArray];