how to retrieve data from SQLite using iphone sdk? - iphone

i have a simple sqllite database with 2 columns and multiple rows. e.g.
Code1 1000
Code2 2000
Code3 3000
Code4 4000
Code5 5000
I want to add all the fields together e.g. code1,code2,code3,code4,code5 and return the total between them to a label in my interface builder. How could i do this using the iphone sdk?are there any tutorials out there? thanks for any help on this.

You'll find a great tutorial here which will cover both the UI and the database part: http://www.techotopia.com/index.php/An_Example_SQLite_based_iOS_4_iPhone_Application
In summary, it would be something like this:
In databaseViewController.h,
#import <UIKit/UIKit.h>
#import "/usr/include/sqlite3.h"
#interface databaseViewController : UIViewController {
UILabel *total;
NSString *databasePath;
sqlite3 *db;
}
#property (retain, nonatomic) IBOutlet UILabel *total;
- (IBAction) getTotal;
#end
In databaseViewController.m,
#import "databaseViewController.h"
#implementation databaseViewController
#synthesize total;
-(void) getTotal
{
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &db) == SQLITE_OK)
{
NSString *totalSQL = [NSString initWithUTF8String: #"SELECT SUM(field2) FROM MyTable"];
const char *total_stmt = [totalSQL UTF8String];
sqlite3_prepare_v2(db, total_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *totalField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
total.text = totalField;
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
}
.
.
.
- (void)viewDidUnload {
self.total = nil;
}
- (void)dealloc {
[total release];
[super dealloc];
}
#end
Something like that... then you just call getTotal in viewDidLoad (or whenever you press a button).

Related

How to retrieve column values into another tableview in iPhone?

I am very beginner to IOS,I have deposit table and expense table in my database I want to retrieve only deposit amount from deposit table and expense amount from expense table into two tableviews means one is for deposit amount tableview and another one is for expense amount tableview in single screen. the below is my dbmodelclass.h in this
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#interface dbModelClass : UIViewController
{
NSMutableDictionary *readDic;
NSMutableArray *readArray;
}
+(NSString *)connectDb;
+(BOOL)createTable;
+(BOOL)createTable3;
+(int)saveData:(NSMutableArray *)data;
+(int)saveData2:(NSMutableArray *)data;
+(NSMutableArray *)getData;
#end
this is my dbmodelclass.m
#import "dbModelClass.h"
#import "Expences.h"
#implementation dbModelClass;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
+(NSString *)connectDb
{
NSArray *docDir=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *dbFolder=[docDir objectAtIndex:0];
NSFileManager *manager=[NSFileManager defaultManager];
if (![manager fileExistsAtPath:dbFolder])
{
[manager createDirectoryAtPath:dbFolder withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString *dbPath=[dbFolder stringByAppendingPathComponent:#"fappDB.sqlite"];
if (![manager fileExistsAtPath:dbPath])
{
[manager copyItemAtPath:[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"fappDB.sqlite"] toPath:dbPath error:nil];
}
NSLog(#"%#",dbPath);
return dbPath;
}
+(BOOL)createTable
{
NSString *dbpath=[dbModelClass connectDb];
sqlite3 *dbObj;
if (sqlite3_open([dbpath UTF8String], &dbObj)==SQLITE_OK)
{
sqlite3_stmt *stmt=nil;
const char *sql="create table deposit(deposit_amount VARCHAR,remarks VARCHAR)";
sqlite3_prepare_v2(dbObj, sql, -1, &stmt, nil);
if (sqlite3_step(stmt)==SQLITE_DONE)
{
NSLog(#"tabel created successfull");
}
else
{
NSLog(#"tabel already created");
}
sqlite3_finalize(stmt);
sqlite3_close(dbObj);
}
return YES;
}
+(BOOL)createTable3;
{
NSString *dbpath=[dbModelClass connectDb];
sqlite3 *dbObj;
if (sqlite3_open([dbpath UTF8String], &dbObj)==SQLITE_OK)
{
sqlite3_stmt *stmt=nil;
const char *sql="create table expense2(expense_title VARCHAR,description VARCHAR,amount VARCHAR,paidcash VARCHAR,date VARCHAR,remarks VARCHAR)";
sqlite3_prepare_v2(dbObj, sql, -1, &stmt, nil);
if (sqlite3_step(stmt)==SQLITE_DONE)
{
NSLog(#"tabel created successfull");
}
else
{
NSLog(#"tabel already created");
}
sqlite3_finalize(stmt);
sqlite3_close(dbObj);
}
return YES;
}
+(int)saveData:(NSMutableArray *)data
{
sqlite3 *dbObj;
sqlite3_stmt *stmt=nil;
NSString *dbPath=[dbModelClass connectDb];
const char *sql=[[NSString stringWithFormat:#"insert into deposit(deposit_amount,remarks) values(\"%#\",\"%#\")",[data objectAtIndex:0],[data objectAtIndex:1]]UTF8String];
if (sqlite3_open([dbPath UTF8String], &dbObj)==SQLITE_OK)
{
sqlite3_bind_text(stmt, 1, [[data objectAtIndex:0]UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [[data objectAtIndex:1]UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_prepare_v2(dbObj, sql, -1, &stmt, nil);
if (sqlite3_step(stmt)==SQLITE_DONE)
{
NSLog(#"data insertion stmnt executed properly");
}
else
NSLog(#"data insertion stmnt not executed");
sqlite3_finalize(stmt);
sqlite3_close(dbObj);
}
return sqlite3_last_insert_rowid(dbObj);
}
+(int)saveData2:(NSMutableArray *)data
{
sqlite3 *dbObj;
sqlite3_stmt *stmt=nil;
NSString *dbPath=[dbModelClass connectDb];
const char *sql=[[NSString stringWithFormat:#"insert into expense2(expense_title,description,amount,paidcash,date,remarks) values(\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\")",[data objectAtIndex:0],[data objectAtIndex:1],[data objectAtIndex:2],[data objectAtIndex:3],[data objectAtIndex:4],[data objectAtIndex:5]]UTF8String];
if (sqlite3_open([dbPath UTF8String], &dbObj)==SQLITE_OK)
{
sqlite3_bind_text(stmt, 1, [[data objectAtIndex:0]UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [[data objectAtIndex:1]UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, [[data objectAtIndex:2]UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, [[data objectAtIndex:3]UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, [[data objectAtIndex:4]UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 6, [[data objectAtIndex:5]UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_prepare_v2(dbObj, sql, -1, &stmt, nil);
if (sqlite3_step(stmt)==SQLITE_DONE)
{
NSLog(#"data insertion stmnt executed properly");
}
else
NSLog(#"data insertion stmnt not executed");
sqlite3_finalize(stmt);
sqlite3_close(dbObj);
}
return sqlite3_last_insert_rowid(dbObj);
}
-(NSMutableArray *)getData
{
sqlite3 *dbobj;
NSString *dbpath =[dbModelClass connectDb];
readArray=[[NSMutableArray alloc]init];
if(sqlite3_open([dbpath UTF8String], &dbobj)==SQLITE_OK)
{
sqlite3_stmt *statement=nil;
//**** NSString *string=#"SELECT name FROM emptable";
NSString *string=#"SELECT *FROM deposit WHERE deposit_amount";
const char *query=[string UTF8String];
if(sqlite3_prepare_v2(dbobj, query, -1, &statement, NULL)==SQLITE_OK)
{
while (sqlite3_step(statement)==SQLITE_ROW)
{
readDic=[[NSMutableDictionary alloc] init];
[readDic setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)] forKey:#"deposit_amount"];
// NSString *aName=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
// NSString *pwd=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
//[readDic setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)] forKey:#"remarks"];
// [readArray addObject:aName];
// [readArray1 addObject:pwd];
[readArray addObject:readDic];
// NSLog(#"%#",readDic);
}
}
sqlite3_finalize(statement);
}
NSLog(#"%#",readArray);
sqlite3_close(dbobj);
return readArray;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
This is my netviewcontroller.h
#import <UIKit/UIKit.h>
#interface NetViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>//DepositTable *depositCo
{
IBOutlet UILabel *depositLabel,*expenseLabel,*netvalueLabel;
IBOutlet UITextField *netvalueText;
IBOutlet UITableView *depositTable,*expenseTable;
}
#property (strong, nonatomic) UINavigationController *navigationController;
#property(strong,nonatomic)UILabel *depositLabel,*expenseLabel,*netvalueLabel;
#property(strong,nonatomic)UITextField *netvalueText;
#property(strong,nonatomic)UITableView *depositTable,*expenseTable;
-(IBAction)netvalue:(id)sender;
#end
This my netviewcontroller.m
#import "NetViewController.h"
#import "dbModelClass.h"
#interface NetViewController ()
#end
#implementation NetViewController
#synthesize depositLabel,expenseLabel,netvalueLabel,depositTable,expenseTable,netvalueText;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[dbModelClass connectDb];
[dbModelClass getData];
NSMutableArray *issuesArray = [[NSMutableArray alloc]init]; [dbModelClass financeappDB:#"SELECT * FROM deposit" resultsArray:issuesArray];
NSLog(#"contents count:%d",[issuesArray count]);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)netvalue:(id)sender
{
}
#end
Please help me
There are several solutions to your question.
The best solution is actually the easiest.
Master viewController with two embedded tableViewControllers, each presenting and managing one table from your database.
During viewDidLoad, you will create an instance of each tableViewController, set it's frame to locate on the desired coordinates of your master view and add it to the master view.
Now you can have a clean and simple delegate model for each table and if you keep the instance of each tableViewController available within the master view controller (allocate as properties), you will be able to communicate to each table from the master view.
The more complicated way is to add two tableView to the master view xib, wire them both up to the datasource and delegate methods in the master viewController and then test each call to the delegate methods to determine which tableView called the method. I've done it but it's a pain to maintain in the long run.
You are not doing things good :).
Why you ar creating an object witch inherits from a UIViewController to manager the DataBase, you can just create an object that inherits from NSObject.
In the getData methode you are asking the data just for the deposit table, you should pass parameters ( table name and amount) to your methode to know if you want data from deposit table or expense2 table.
And finally in the NetViewController class you can do :
...
[dbModelClass connectDb];
NSArray *depositData = [dbModelClass getDataWith....]; // here you fetch your database with deposit table and others param
NSArray * expenseData = [dbModelClass getDataWith....]; // Here you fetch your database with expensive table and others param
Edited answer :
You can do like this for example :
-(NSMutableArray *)getDataForTable:(NSString *)tableName withAmount:(NSString *)amountName
{
sqlite3 *dbobj;
NSString *dbpath =[dbModelClass connectDb];
readArray=[[NSMutableArray alloc]init];
if(sqlite3_open([dbpath UTF8String], &dbobj)==SQLITE_OK)
{
sqlite3_stmt *statement=nil;
//**** NSString *string=#"SELECT name FROM emptable";
NSString *string = [NSString stringWithFormat:#"SELECT *FROM %# WHERE %#",tableName,amountName];
const char *query=[string UTF8String];
if(sqlite3_prepare_v2(dbobj, query, -1, &statement, NULL)==SQLITE_OK)
{
while (sqlite3_step(statement)==SQLITE_ROW)
{
readDic=[[NSMutableDictionary alloc] init];
[readDic setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)] forKey:#"deposit_amount"];
// NSString *aName=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
// NSString *pwd=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
//[readDic setObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)] forKey:#"remarks"];
// [readArray addObject:aName];
// [readArray1 addObject:pwd];
[readArray addObject:readDic];
// NSLog(#"%#",readDic);
}
}
sqlite3_finalize(statement);
}
Add this
-(NSMutableArray *)getDataForTable:(NSString *)tableName withAmount:(NSString *)amountName in the dbModelClass.h
and now you can call this methode in NetViewController by passing it the table name and the amount :
[dbModelClass connectDb];
NSArray * depositResult = [dbModelClass getDataWith:#"deposite" amountName:#"deposit_amount"];
// Do same thing for the other table by passing it the appropriate names.
PS : this code is not tested and you should refactor it, it's just to show you how to pass parameters for a methode

trying to copy array from one class to array but copied array showing null

Hi, I am trying to get array from StudentDbwithsearchbarViewController class to SearchBarDB class but resultant array not having any data it is giving null Array. Please help me out with this.
thanks in advance
#import <UIKit/UIKit.h>
#interface StudentDbwithsearchbarViewController : UIViewController<UITableViewDelegate,UITableViewDataSource> {
IBOutlet UITextField *txtMarks,*txtSname;
IBOutlet UITableView *tableStudents;
NSMutableArray *arrStudents;
}
#property(nonatomic,retain) NSMutableArray *arrStudents;
-(IBAction)saveStudentDetails;
-(IBAction)gotoSearchpage;
#end
#implementation StudentDbwithsearchbarViewController
#synthesize arrStudents;
- (void)viewDidLoad {
[super viewDidLoad];
arrStudents = [[DbStudent getStudentRecords]retain];
NSLog(#"%#",arrStudents);
NSLog(#"%d",[arrStudents retainCount]);
}
#import "DbStudent.h"
+(NSMutableArray*)getStudentRecords{
NSArray *arrDocPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *strDestPath = [NSString stringWithFormat:#"%#/Student5.sqlite",[arrDocPath objectAtIndex:0]];
NSMutableArray *arrStudents = [[NSMutableArray alloc]init];
sqlite3 *db;
if(sqlite3_open([strDestPath UTF8String], &db)==SQLITE_OK)
{
NSString *query = #"SELECT * FROM Student";
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 sno = sqlite3_column_int(studentStmt, 0);
NSString *sname = [NSString stringWithUTF8String: sqlite3_column_text(studentStmt, 1)];
float marks = sqlite3_column_double(studentStmt, 2);
Student *st = [[Student alloc]init];
st.Sno = sno;
st.Sname = sname;
st.marks = marks;
[arrStudents addObject:st];
}
}
}
return arrStudents;
}
#import "SearchBarDB.h"
#import"StudentDbwithsearchbarViewController.h"
- (void)viewDidLoad {
[super viewDidLoad];
StudentDbwithsearchbarViewController *sbd = [[StudentDbwithsearchbarViewController alloc]init];
NSLog(#"%d",[sbd.arrStudents retainCount]);
NSLog(#"%#",sbd.arrStudents);
// arrstudentBase = [sbd.arrStudents copy];
arrMatchedString = [[NSMutableArray alloc]init];
}
Lots of potential problems, no definitive answer without a clue as to what you've tried or how you've determined that it failed.
methods should not be prefixed with get; just call it studentRecords or fetchStudentRecords
your memory management code is all over the place; you'll be leaking that array, at the least.
retainCount is useless, don't call it.
writing raw SQL is a waste of time; at least use a wrapper like FMDB or, better yet, move to CoreData
Best guess for failure: the database doesn't exist or the query fails. Have you stepped through the query code?

Storing and retrieving data from sqlite database

I am building an app which contains a form in one view,in which the user fills all the fields and when he clicks the save button the data must be saved in to database and after navigating back,there's another view which, when entered, must show the saved data(event).
I have created a database and have gone through several sqlite3 tutorials;
I have done all other changes to my code according to my requirement. However, when I use this statement to check whether data is inserted in database:
SELECT * FROM reminders;
I am getting nothing and I am confused whether data is inserted or not.
How do I save it properly, and how do I retrieve data from database to use and display it in other view?
First you should create the sqlite3 database file (check this link), then you should include it into your project. Now to connect to it you can use the following code:
#pragma mark -
#pragma mark Create/Load Database
+ (void)createEditableCopyOfDatabaseIfNeeded {
// First, test for existence.
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentsDirectory = [paths objectAtIndex:0];
NSString * writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"DATABASENAME.DB"];
BOOL success;
NSFileManager * fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) {
return;
}
// The writable database does not exist, so copy the default to the appropriate location.
NSError * error;
NSString * defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"DATABASENAME.DB"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
+ (sqlite3 *)getDBConnection {
[DatabaseController createEditableCopyOfDatabaseIfNeeded];
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentsDirectory = [paths objectAtIndex:0];
NSString * path = [documentsDirectory stringByAppendingPathComponent:#"DATABASENAME.DB"];
// Open the database. The database was prepared outside the application.
sqlite3 * newDBConnection;
if (sqlite3_open([path UTF8String], &newDBConnection) == SQLITE_OK) {
//NSLog(#"Database Successfully Opened :)");
} else {
//NSLog(#"Error in opening database :(");
}
return newDBConnection;
}
then to insert a record you can use this code:
+ (void)insertEvent:(Event *)newEvent {
sqlite3 * connection = [DatabaseController getDBConnection];
const char * text = "INSERT INTO Event (Serial, Name, Date) VALUES (?, ?, ?)";
sqlite3_stmt * insert_statement;
int prepare_result = sqlite3_prepare_v2(connection, text, -1, &insert_statement, NULL);
if ((prepare_result != SQLITE_DONE) && (prepare_result != SQLITE_OK)) {
// Error
sqlite3_close(connection);
return;
}
sqlite3_bind_int(insert_statement, 1, newEvent.Serial);
sqlite3_bind_text(insert_statement, 2, [newEvent.Name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_double(insert_statement, 3, [newEvent.Date timeIntervalSince1970]);
int statement_result = sqlite3_step(insert_statement);
if ((statement_result != SQLITE_DONE) && (statement_result != SQLITE_OK)) {
//Error
sqlite3_close(connection);
return;
}
sqlite3_finalize(insert_statement);
// Get the Id of the inserted event
int rowId = sqlite3_last_insert_rowid(connection);
newEvent.Id = rowId;
sqlite3_close(connection);
}
now to get an event:
+ (Event *)getEventById:(int)id {
Event * result = nil;
sqlite3 * connection = [DatabaseController getDBConnection];
const char * text = "SELECT * FROM Event WHERE Id = ?";
sqlite3_stmt * select_statement;
int prepare_result = sqlite3_prepare_v2(connection, text, -1, &select_statement, NULL);
if ((prepare_result != SQLITE_DONE) && (prepare_result != SQLITE_OK)) {
// error
sqlite3_close(connection);
return result;
}
sqlite3_bind_int(select_statement, 1, id);
if (sqlite3_step(select_statement) == SQLITE_ROW) {
result = [[[Event alloc] init] autorelease];
result.Id = sqlite3_column_int(select_statement, 0);
result.Serial = sqlite3_column_int(select_statement, 1);
result.Name = (((char *) sqlite3_column_text(select_statement, 2)) == NULL)? nil:[NSString stringWithUTF8String:((char *) sqlite3_column_text(select_statement, 2))];
result.Date = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_double(select_statement, 3)];
}
sqlite3_finalize(select_statement);
sqlite3_close(connection);
return (result);
}
Here is a blog post that should get you pointed in the right direction, pretty useful to me so sharing it with you.:P
http://dblog.com.au/iphone-development-tutorials/iphone-sdk-tutorial-reading-data-from-a-sqlite-database/
you can check whether your data has been saved or not by checking the database table. Go to Users>your computer name>Library>Application support>iphone Simulator>4.3(your version of ios)>Application.. Then look for your Application,go to documents and open the sqlite file. Here you can see the data.
You should use FMDB to reduce the complexity of your code.
It is an Objective-C wrapper around SQLite.
FMDB on github
This code used for storing data and retriving data from sqlite data base
First you just add sqlite3 frame work after that write bellow code in objective-c
ViewController.h
#import <UIKit/UIKit.h>
#import "sqlite3.h"
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *firstName;
#property (weak, nonatomic) IBOutlet UITextField *lastName;
#property (weak, nonatomic) IBOutlet UITextField *state;
#property (weak, nonatomic) IBOutlet UITextField *mobileNum;
- (IBAction)saveButton:(id)sender;
- (IBAction)featchButton:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *label;
#property NSString *myDatabase;
#property sqlite3 *marksDB;
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *docsDir;
NSArray *dirPaths;
dirPaths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir=dirPaths[0];
_myDatabase=[[NSString alloc]initWithString:[docsDir stringByAppendingString:#"marks.db"]];
NSLog(#"My Data base %#",_myDatabase);
NSFileManager *fileMgr=[NSFileManager defaultManager];
if ([fileMgr fileExistsAtPath:_myDatabase]==NO)
{
const char *dbpath=[_myDatabase UTF8String];
if (sqlite3_open(dbpath, &_marksDB)==SQLITE_OK)
{
char *errMsg;
const char *sql_stmt="CREATE TABLE IF NOT EXISTS MARKS(ID INTEGER PRIMARY KEY AUTOINCREMENT ,FIRST NAME TEXT,LAST NAME TEXT,STATE TEXT,MOBILE INTEGER )";
if (sqlite3_exec(_marksDB, sql_stmt, NULL, NULL, &errMsg)!=SQLITE_OK)
{
_label.text=#"Failed to create Table";
}
sqlite3_close(_marksDB);
}
else
{
_label.text=#"Failed to Create/Open Database";
}
}
}
- (IBAction)saveButton:(id)sender {
sqlite3_stmt *statement;
const char *dbpath=[_myDatabase UTF8String];
if (sqlite3_open(dbpath, &_marksDB)==SQLITE_OK)
{
NSString *insertSQL=[NSString stringWithFormat:#"INSERT INTO MARKS(firstname,lastname,state,mobile )VALUES(\"%#\",\"%#\",\"%#\",\"%#\")",_firstName.text,_lastName.text,_state.text,_mobileNum.text ];
const char *insert_stmt=[insertSQL UTF8String];
sqlite3_prepare_v2(_marksDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement)==SQLITE_DONE)
{
_label.text=#"Contact Added";
_firstName.text=#"";
_lastName.text=#"";
_state.text=#"";
_mobileNum.text=#"";
}
else
{
_label.text=#"Failed to Add Contact";
}
sqlite3_finalize(statement);
sqlite3_close(_marksDB);
}
}
- (IBAction)featchButton:(id)sender {
const char *dbpath=[_myDatabase UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &_marksDB)==SQLITE_OK)
{
NSString *query=[NSString stringWithFormat:#"SELECT firstname,lastname,state,mobile, FROM MARKS WHERE firstname=\"%#\"",_firstName.text];
const char *query_stmt=[query UTF8String];
if (sqlite3_prepare_v2(_marksDB, query_stmt, -1, &statement, NULL)==SQLITE_OK)
{
if (sqlite3_step(statement)==SQLITE_ROW)
{
NSString *first=[[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];
_firstName.text=first;
NSString *lastName=[[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 1)];
_lastName.text=lastName;
NSString *state=[[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 2)];
_state.text=state;
NSString *mobile=[[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 3)];
_mobileNum.text=mobile;
_label.text=#"Match Found";
}
else
{
_label.text=#"Not Matched";
_lastName.text=#"";
_state.text=#"";
_mobileNum.text=#"";
}
sqlite3_finalize(statement);
}
sqlite3_close(_marksDB);
}
}
#end

Program received signal "EXC_Bad_Access" NSMutableArray

if I try and reun the code below I get an EXE_bad_access message on [categoryList count]
NSMutableArray *categoryList = [[CategoryItem alloc] getAll];
NSLog(#"number of items is %#", [categoryList count]);
The class is below
#import "CategoryItem.h"
#import "SQLite.h"
#interface CategoryItem : NSObject {
NSInteger ID;
NSInteger SortOrder;
NSString *Name;
NSString *ShoppingImage;
}
#property (nonatomic, nonatomic) NSInteger SortOrder;
#property (nonatomic, retain) NSString * Name;
#property (nonatomic, retain) NSString * ShoppingImage;
#property (nonatomic, nonatomic) NSInteger ID;
- (id)initWithObject:(NSInteger)itemID;
-(NSMutableArray *)getAll;
#end
#implementation CategoryItem
#synthesize ShoppingImage;
#synthesize Name;
#synthesize ID;
#synthesize SortOrder;
- (id)initWithObject:(NSInteger)itemID {
if ((self = [super init])) {
sqlite3 *database;
// Open the database. The database was prepared outside the application.
if (sqlite3_open([[SQLite fullFilePath] UTF8String], &database) == SQLITE_OK) {
// Get the primary key for all books.
const char *sql = "SELECT ID, Name, ShoppingImage, SortOrder FROM CategoryItem WHERE ID =?";
sqlite3_stmt *statement;
// Preparing a statement compiles the SQL query into a byte-code program in the SQLite library.
// The third parameter is either the length of the SQL string or -1 to read up to the first null terminator.
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
// We "step" through the results - once for each row.
sqlite3_bind_int(statement, 1, itemID);
while (sqlite3_step(statement) == SQLITE_ROW) {
// The second parameter indicates the column index into the result set.
self.ID = itemID;
self.Name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
self.ShoppingImage = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 2)];
self.SortOrder = sqlite3_column_int(statement, 3);
}
}
// "Finalize" the statement - releases the resources associated with the statement.
sqlite3_finalize(statement);
} else {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(database);
NSLog(#"Failed to open database with message '%s'.", sqlite3_errmsg(database));
// Additional error handling, as appropriate...
}
}
return self;
}
-(NSMutableArray*)getAll{
NSMutableArray *listArray = [[[NSMutableArray alloc] init] autorelease];
sqlite3 *database;
// Open the database. The database was prepared outside the application.
if (sqlite3_open([[SQLite fullFilePath] UTF8String], &database) == SQLITE_OK) {
// Get the primary key for all books.
const char *sql = "SELECT ID, Name, ShoppingImage, SortOrder FROM CategoryItem ORDER BY SortOrder";
sqlite3_stmt *statement;
// Preparing a statement compiles the SQL query into a byte-code program in the SQLite library.
// The third parameter is either the length of the SQL string or -1 to read up to the first null terminator.
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK)
{
// We "step" through the results - once for each row.
while (sqlite3_step(statement) == SQLITE_ROW)
{
// The second parameter indicates the column index into the result set.
CategoryItem *categoryItem = [[CategoryItem alloc] init];
categoryItem.ID = sqlite3_column_int(statement, 0);
categoryItem.Name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
categoryItem.ShoppingImage = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 2)];
categoryItem.SortOrder = sqlite3_column_int(statement, 3);
[listArray addObject:categoryItem];
[categoryItem release];
categoryItem = nil;
}
}else{
printf( "could not prepare statemnt: %s\n", sqlite3_errmsg(database) );
}
// "Finalize" the statement - releases the resources associated with the statement.
sqlite3_finalize(statement);
} else {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(database);
NSLog(#"Failed to open database with message '%s'.", sqlite3_errmsg(database));
// Additional error handling, as appropriate...
}
//NSLog(#"this is the list array count %#", [listArray count]);
return listArray;
}
- (void)dealloc {
[super dealloc];
[Name release];
[ShoppingImage release];
}
#end
It doesn't seem right the way you create your CategoryItem. You are calling allocbut not any init... method. You may want to use the initWithObject method that you have provided in your implementation.
From Apple docs:
It takes two steps to create an object
using Objective-C. You must:
Dynamically allocate memory for the
new object
Initialize the newly
allocated memory to appropriate values
An object isn’t fully functional until
both steps have been completed. Each
step is accomplished by a separate
method but typically in a single line
of code:
id anObject = [[Rectangle alloc]
init];
EDIT:
Beyond the initialization problem, there seems to be a conceptual problem (pointed out by #Terry Wilcox):
Calling the method getAllon an instance does not seem to make sense and therefore should be defined as a class method instead:
+ (NSMutableArray*)getAll;
and should be called like this:
NSMutableArray *categoryList = [CategoryItem getAll];
EDIT 2:
Your log statement does not seem right either. [categoryList count]returns a NSUIntegerand you are trying to print an object with %#. Use %iinstead:
NSLog(#"number of items is %i", [categoryList count]);
This code:
NSMutableArray *categoryList = [[CategoryItem alloc] getAll];
doesn't make sense. If getAll is a class method on CategoryItem, then it should be defined as
+ (NSMutableArray*)getAll;
and you should call it as
NSMutableArray *categoryList = [CategoryItem getAll];
Then categoryList will be an array that you don't own, so you may want to retain it when you get it.

Using Sqlite in iphone development: if i open the database in the init function, it's inaccessible in my other functions. Any ideas?

I'm trying to use sqlite in a 'data services' class like below. I keep getting an error code 1 when calling 'sqlite3_prepare_v2'. The logs certainly back up that the database is getting opened before my recipeNames function is called. I'm so stumped! Is it a memory management thing with the sqlite3 *db ? Eg is it getting freed when i don't want it to?
I'm certain the code is OK otherwise, because if i put the sqlite_open in the recipeNames function, it works great. It's just if i try to open it in the init method it fails. Thanks a lot guys.
My header:
#import <Foundation/Foundation.h>
#include <sqlite3.h>
#interface DataServices : NSObject {
sqlite3 *db;
int dbrc;
}
- (NSMutableArray *) recipeNames;
#end
Implementation file:
#import "DataServices.h"
#import "MenuMakerAppDelegate.h"
#include <sqlite3.h>
#implementation DataServices
- (id)init {
[super init];
// my init stuff here
// Get the database name
const char *dbPathUtf8 = [((MenuMakerAppDelegate*)[UIApplication sharedApplication].delegate).dbFilePath UTF8String];
// Open the database
NSLog(#"opening db");
sqlite3_open (dbPathUtf8, &db);
NSLog(#"opened db");
return self;
}
- (void)dealloc {
// My dealloc stuff here
NSLog(#"Closing DB");
sqlite3_close(db);
[super dealloc];
}
- (NSMutableArray *) recipeNames {
// Create the empty array to return
NSMutableArray *arr = [[[NSMutableArray alloc] init] autorelease];
// The SQL
NSString *sql = #"select recipe from recipes";
const char *sqlUtf8 = [sql UTF8String];
// Make the prepared statement (like C# SqlCommand)
sqlite3_stmt *dbps;
dbrc=sqlite3_prepare_v2(db, sqlUtf8, -1, &dbps, NULL); // FAILS HERE !!!
if (dbrc) NSLog(#"Prepare!!! %d", dbrc);
// Loop thru rows
while (sqlite3_step(dbps) == SQLITE_ROW) {
NSString *recipe = [NSString stringWithUTF8String:(char*)sqlite3_column_text(dbps,0)];
[arr addObject:recipe];
}
// Get rid of the command
sqlite3_finalize(dbps);
// Return the array that was autoreleased before
return arr;
}
#end
On a hunch:
NSLog(#"opening db %s", dbPathUtf8);
int result = sqlite3_open(dbPathUtf8, &db);
NSLog(#"sqlite3_open returned %d", result);
I'm betting that dbPathUtf8 is null and that sqlite3_open is returning an error. 1 is SQLITE_ERROR (SQL error or missing database), which probably means db is NULL.