How to filter NSDictonary in UISearchBar? - ios

In my app i am using UITableView To display List of items And UISearchBar to Filter the List Of items. All the data, i am reading it from sqlite3.
Following is my code:
below code is used to retrieve the data from Local DB and save the data into NSMutableDictionary called dict and the the dict is added into NSMutableArray
arr_AllTableData.
-(void)dataFromLocalDB
{
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &PSATestDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:#"SELECT * FROM Test"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(PSATestDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
companyName = [[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 9)];
[arr_Name addObject:companyName];
address = [[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 10)];
[arr_Address addObject:address];
number = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 3)];
[arr_TelephoneNo addObject:number];
url = [[NSString alloc]initWithUTF8String:(const char *)sqlite3_column_text(statement, 4)];
[arr_WebAddress addObject:url];
_dict = [[NSMutableDictionary alloc] init];
[_dict setValue:arr_Name forKey:#"Name"];
[_dict setValue:arr_Address forKey:#"Address"];
[_dict setValue:arr_TelephoneNo forKey:#"Number"];
[_dict setValue:arr_WebAddress forKey:#"WebAddress"];
[arr_AllTableData addObject:_dict];
}
sqlite3_finalize(statement);
sqlite3_close(PSATestDB);
}
}
}
Following code is used to display data in UITableView
#pragma mark - UITableView Data source
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (isFiltered == YES)
{
return [filtered_Name count];
}
else
{
return [arr_AllTableData count];
}
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"listCell";
PSAListCell *List = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (isFiltered == YES)
{
List.lbl_name.text = [filtered_Name objectAtIndex:indexPath.row];
}
else
{
List.lbl_name.text = [[_dict objectForKey:#"Name"] objectAtIndex:indexPath.row];
List.lbl_address.text = [[_dict objectForKey:#"Address"] objectAtIndex:indexPath.row];
List.lbl_ContactNO.text = [[_dict objectForKey:#"Number"] objectAtIndex:indexPath.row];
List.lbl_WebAddress.text = [[_dict objectForKey:#"WebAddress"] objectAtIndex:indexPath.row];
}
return List;
}
This is my UISearch Bar implemantion code:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchText.length == 0)
{
// set our boolean flag
isFiltered = NO;
}
else
{
//set our boolean flag
isFiltered = YES;
// Alloc And init our filter NSMutable array
filtered_Name = [[NSMutableArray alloc]init];
//fast enumeration
NSMutableArray *test = [[NSMutableArray alloc]init];
for (NSDictionary *dictionary in arr_AllTableData)
{
NSArray *array = [dictionary objectForKey:#"Name"];
[test addObjectsFromArray:array];
}
for (NSString * name in test)
{
NSRange nameRang = [name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (nameRang.location != NSNotFound)
{
[filtered_Name addObject:name];
}
}
}
[_ListTable reloadData];
}
I want to filter the NSDictionary which contains the data and want to display to the filter data on UITableView and if the data is not available in the dictionary then it need to call a web service?
Can anyone please help me out with this?

you can use NSPredicate to filter content from arr_AllTableData based upon your input string.
you can find filter array with predicate in below link.
http://alexeckermann.com/blog/legacy/filtering-nsarray-with-nspredicates

Related

Passing data from sqlitedatabase to a Detailview

I'm creating an iOS app which is a directory system, where on the first page I load data such as a list of some states in a tableview (from a sqlite database). When clicking on a state only the districts under that particular state have to be displayed in the detailview's tableview. My problem is that when clicking on each district the phonenumber of that district must be shown in the next view controller. Can somebody please help?
This is the firstview.
#implementation firstview
#synthesize ddetails=_ddetails;
#synthesize at,arraydata,show,table;
static firstview *_database;
+ (firstview*)database {
if (_database == nil) {
_database = [[firstview alloc] init];
}
return _database;}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [theauthors count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 30;}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
menu *me = [self.theauthors objectAtIndex:indexPath.row];
cell.textLabel.text=me.state;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = selectedCell.textLabel.text;
[_button setTitle:cellText forState:UIControlStateNormal];
menu *infos=[theauthors objectAtIndex:indexPath.row];
self.ddetails = [self.storyboard instantiateViewControllerWithIdentifier:#"detailViewController"] ;
_ddetails.uniqueId=infos.id;
// NSLog(#"%#",infos.state);
// NSLog(#"%d",infos.id);
[self.navigationController pushViewController:_ddetails animated:NO];
}
-(NSMutableArray *) authorList{
theauthors = [[NSMutableArray alloc]init] ;
show=[[NSMutableArray alloc]init];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"menu.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
NSString *query =[NSString stringWithFormat:#"SELECT id,category FROM category "];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(db, [query UTF8String], -1, &selectstmt, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}else{
while (sqlite3_step(selectstmt)==SQLITE_ROW) {
menu * men = [[menu alloc] init];
men.id= sqlite3_column_int(selectstmt,0);
men.state=[NSString stringWithUTF8String:(char *) sqlite3_column_text(selectstmt,1)];
[theauthors addObject:men];
// NSLog(#"%#",men.category);
// NSLog(#"%d",men.id);
}
}
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
return theauthors;
}
}
- (detailsnews *)Detailsnews:(int)uniqueId{
NSLog(#"%d",uniqueId);
detailsnews *get=nil;
_the=[[NSMutableArray alloc]init];
_gets=[[NSMutableArray alloc]init];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"menu.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
NSString *sqls =[NSString stringWithFormat:#"SELECT * FROM menulist where category=%d",uniqueId];
// NSLog(#"%d",uniqueId);
sqlite3_stmt *selectstmt6;
if(sqlite3_prepare(db, [sqls UTF8String], -1, &selectstmt6, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}else{
while (sqlite3_step(selectstmt6)==SQLITE_ROW) {
// NSLog(#"%d",uniqueid);
int totalValue = 0;
int uniqueId = sqlite3_column_int(selectstmt6,0);
// NSLog(#"%d",uniqueid);
[_gets addObject:[NSNumber numberWithInt:uniqueId]];
for(NSNumber *number in _gets) // Use fast enumeration to iterate through the array
{
totalValue = [number intValue];
// NSLog(#"%d",totalValue);
}
char *nameChars = (char *) sqlite3_column_text(selectstmt6, 2);
NSString *name = [[NSString alloc] initWithUTF8String:nameChars];
char *rec = (char *) sqlite3_column_text(selectstmt6, 1);
NSString *rece = [[NSString alloc] initWithUTF8String:rec];
// NSLog(#"%#",rece);
[_the addObject:rece];
NSMutableString * result = [[NSMutableString alloc] init];
for (NSObject * obj in _the)
{
[result appendString:[obj description]];
result = [_the componentsJoinedByString: #"\r"];
// NSLog(#"%#",result);
}
//[_the addObject:[NSNumber numberWithInt:uniqueid]];
// int totalValue = 0;
// for(NSNumber *number in _the) // Use fast enumeration to iterate through the array
// {
// totalValue = [number intValue];
// NSLog(#"%d",totalValue);
// }
//
// NSMutableString * result = [[NSMutableString alloc] init];
// int totalValue = 0;
//for (NSObject * obj in _the)
// {
// [result appendString:[obj description]];
// result = [_the componentsJoinedByString: #"\r"];
// NSLog(#"%#",result);
// }
//NSArray *arr=[result componentsSeparatedByString:#"\r"];
// NSMutableString * vgh = [[NSMutableString alloc] init];
// for (NSObject * obj in arr)
// {
//[vgh appendString:[obj description]];
// vgh = [arr componentsJoinedByString: #"\r"];
// }
get = [[detailsnews alloc] initWithUniqueId:totalValue district:result phonenumber:name ];
//NSLog(#"%#",_the);
}
}
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
return get;
}
}
detailview controller
- (void)viewDidLoad
{
[super viewDidLoad];
detailsnews *details = [[firstview database]
Detailsnews:_uniqueId];
if (details != nil) {
NSArray *arrComponents = [details.district componentsSeparatedByString:#"\r"];
arr = [[NSMutableArray alloc] init];
for(int i = 0; i < [arrComponents count] ;i++)
{
NSString *str = [arrComponents objectAtIndex:i];
[arr addObject:str];
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arr count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 30;}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
detailsnews *details = [[firstview database]
Detailsnews:_uniqueId];
cell.textLabel.text=[arr objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = selectedCell.textLabel.text;
[button2 setTitle:cellText forState:UIControlStateNormal];
detailsnews *details = [[firstview database]
Detailsnews:_uniqueId];
//NSLog(#"%d",details.uniqueId);
// NSLog(#"%#",details.rece);
// detailsnews *infos=[arr objectAtIndex:indexPath.row];
self.ddetails = [self.storyboard instantiateViewControllerWithIdentifier:#"phonelistViewController"] ;
_ddetails.uniqueId=details.uniqueId;
// NSLog(#"%d",details.uniqueId);
[self.navigationController pushViewController:_ddetails animated:NO];
}
You need to Pass the data including the phoneNumbers from first stateViewController to District and then from District to DetailsPage…I would suggest pass an NSdictionary which Includes the data from one view to another such as..In second ViewController declare a global Dictionary as mainDictionary..
and in didSelectRowAtIndexPath just pass the data as
self.ddetails = [self.storyboard instantiateViewControllerWithIdentifier:#"phonelistViewController"] ;
_ddetails.mainDict=AllThe Details;
Do the same thing with PhoneNumbers also

How to get selected row's title and value in uipickerview?

in my iphone project i need to get data from sqlite and show it on uipickerview then with selected row's value i need to fill another uipickerview
in my table T_REGION there is two columns ID and NAME
this is how i get REGION list
- (NSArray*) getRegions
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:#"select ID,NAME from T_REGION"];
const char *query_stmt = [querySQL UTF8String];
NSMutableArray *resultArray = [[NSMutableArray alloc]init];
if (sqlite3_prepare_v2(database,
query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *name = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(statement, 1)];
[resultArray addObject:name];
}
sqlite3_reset(statement);
return resultArray;
}
else
{
NSLog(#"problem");
}
}
return nil;
}
as you see i cant fill ID column to array only name column returns i need ID column to fill another uipickerview (you may think as country - city relationship)
this is my first problem
now this is how i fill my pickerview
first in viewDidLoad method i get array:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self getdata];
}
- (void)getdata {
dataRegion = [[NSArray alloc] initWithArray: [[DBHelper getSharedInstance:#"2_program.db"]getRegions]];
}
and my uipickerview delegate methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if (pickerView.tag == 1)
return [dataRegion count];
else
return 0; //[countryTypes count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (pickerView.tag == 1)
return [dataRegion objectAtIndex:row];
else
return #"";
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
if (pickerView.tag == 1) {
NSString *categoryType = [dataRegion objectAtIndex:[pickerView selectedRowInComponent:0]];
[btnBolge setTitle:categoryType forState:UIControlStateNormal];
}else {
}
}
what i want is what select option tag do in html. i need 2 columns but show only 1 and get the selected row's value not text
1- how can i return 2 columns in getRegions function?
2- how can i show only name column in uipickerview and get its selected row's id column?
Try This.. May be help full..
Like this you can add both array as dictionary
NSMutableArray *nameArray = [[NSMutableArray alloc]initWithObjects:#"Come",#"Say",#"Go", nil];
NSMutableArray *regionArray = [[NSMutableArray alloc]initWithObjects:#"Hi",#"Hello",#"Bye", nil];
NSMutableArray *mainArray = [[NSMutableArray alloc]init];
for (int index = 0; index<regionArray.count; index++) {
NSMutableDictionary *dataAddDic = [[NSMutableDictionary alloc]init];
[dataAddDic setValue:[nameArray objectAtIndex:index] forKeyPath:#"name"];
[dataAddDic setValue:[regionArray objectAtIndex:index] forKeyPath:#"region"];
[mainArray addObject:dataAddDic];
}
NSLog(#"Data Print %#",mainArray);
After you need to change you delegate functions
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if (pickerView.tag == 1)
return [mainArray count];
else
return 0; //[countryTypes count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (pickerView.tag == 1)
return [[mainArray objectAtIndex:row] valueForKey:#"region"];
else
return #"";
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
if (pickerView.tag == 1) {
NSString *categoryType = [[mainArray objectAtIndex:row] valueForKey:#"name"];
[btnBolge setTitle:categoryType forState:UIControlStateNormal];
}else {
}
}
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:#"select ID,NAME from T_REGION"];
const char *query_stmt = [querySQL UTF8String];
NSMutableArray *resultArray = [[NSMutableArray alloc]init];
if (sqlite3_prepare_v2(database,query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *id = [[NSString alloc] initWithUTF8Strin
(const char *) sqlite3_column_text(statement, 0)];
NSString *name = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(statement, 1)];
NSDictionary *dict = #{id:name};
[resultArray addObject:dict];
}
sqlite3_reset(statement);
return resultArray;
}
else
{
NSLog(#"problem");
}
}
return nil;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (pickerView.tag == 1){
NSDictionary *region = [dataRegion objectAtIndex:row];
NSArray *keys = [region allKeys];
return region[[keys[0]];
}
else{
return #"";
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
if (pickerView.tag == 1) {
NSDictionary *region = [dataRegion objectAtIndex:row];
NSArray *keys = [region allKeys];
[btnBolge setTitle:region[keys[0]] forState:UIControlStateNormal];
}else {
}
}

How to add JSON data to a NSMutableArray?

Im trying to read rows from my SQLite DB and then convert the data to JSON and put it into an NSMutableArray. I then want to loop over the array and print the data into my table view.
This is what i do to load the data from SQLite:
entries = [[NSMutableArray alloc] init];
NSString *sql = [NSString stringWithFormat:#"SELECT * FROM chatHistory GROUP BY channelID ORDER BY time DESC"];
sqlite3_stmt *statement;
if(sqlite3_prepare_v2([box db], [sql UTF8String], -1, &statement, nil) == SQLITE_OK) {
while(sqlite3_step(statement) == SQLITE_ROW) {
char *field1 = (char *) sqlite3_column_text(statement, 0);
NSString *channelID = [[NSString alloc] initWithUTF8String:field1];
char *field2 = (char *) sqlite3_column_text(statement, 0);
NSString *sender = [[NSString alloc] initWithUTF8String:field2];
char *field3 = (char *) sqlite3_column_text(statement, 0);
NSString *message = [[NSString alloc] initWithUTF8String:field3];
char *field4 = (char *) sqlite3_column_text(statement, 0);
NSString *recipient = [[NSString alloc] initWithUTF8String:field4];
char *field5 = (char *) sqlite3_column_text(statement, 0);
NSString *time = [[NSString alloc] initWithUTF8String:field5];
NSString *messageArray = [[NSString alloc] initWithFormat:#"[{ \"channelID\":\"%#\", \"sender\":\"%#\", \"message\":\"%#\", \"recipient\":\"%#\", \"time\":\"%#\"}]", channelID, sender, message, recipient, time];
// Convert to JSON object:
NSArray *jsonObject = [NSJSONSerialization JSONObjectWithData:[messageArray dataUsingEncoding:NSUTF8StringEncoding]
options:0 error:NULL];
[entries addObject:jsonObject];
Now here is how i try to add it to my table view:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ConvCell";
ConvCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ConvCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSArray *tableData = [self.entries valueForKey:#"message"];
NSLog(#"Message=%#", tableData);
cell.visitorName.text = (NSString *) [self.entries objectAtIndex:indexPath.row]; // This trows an error
cell.visitorAvatar.image = [UIImage imageNamed:#"hello.png"];
cell.messageTime.text = #"19.10";
return cell;
}
The error im getting is:
exception 'NSInvalidArgumentException', reason: '-[__NSCFArray length]: unrecognized selector sent to instance 0xa0cfc40'
Any ideas what I'm doing wrong?
Your use of JSON is interesting, it's just a short code way of creating dictionaries and nesting them in arrays. There are more containers than you really need and you could just create the dictionaries without all of the JSON wrangling.
That said, your actual error is because this line:
cell.visitorName.text = (NSString *) [self.entries objectAtIndex:indexPath.row];
should be
cell.visitorName.text = (NSString *) [tableData objectAtIndex:indexPath.row];
because you have those nested arrays are you aren't digging right to the bottom of them...
Your setup is not ideal. That being said...
You are casting your array of messages to a string.
[self.entries objectAtIndex:indexPath.row]
should return an array, not a string. What you want is something like this:
NSArray* jsonArray = [self.entries objectAtIndex:indexPath.row];
NSDictionary *dictionary = [jsonArray lastObject];
cell.visitorName.text = dictionary[#"sender"];
You can see that wrapping your one dictionary into an array does not really make any sense. Instead you could leave out the [...] in your JSON template. Then you would have
NSDictionary *dictionary = [self.entries objectAtIndex:indexPath.row];
BTW, the proper way to do this is to have a custom object Message with appropriate properties that you set right in your database fetch.

SQLite and UITableView: Crash after numberOfRowsInSection

First I would like to make clear that I do not want to use Core Data in this case.
My Problem: whenever my tableview's delegate methodd: numberOfRowsInSection is called, the application crashes with nothing more than an (lldb) error message.
First I have two classes which helps me retrieve rows from my SQLite database.
sqlite.m:
#import "sqlite.h"
#import <sqlite3.h>
#implementation sqlite
#synthesize carbohydrates = _carbohydrates;
#synthesize name = _name;
#synthesize fat = _fat;
#synthesize kcal = _kcal;
- (id)initWithName:(NSString *)name2 carbs:(NSNumber *)carbs2
fat:(NSNumber *)fat2 kcal:(NSNumber*)kcal2 {
if ((self = [super init])) {
self.carbohydrates = carbs2;
self.name = name2;
self.fat = fat2;
self.kcal = kcal2;
}
return self;
}
- (void) dealloc {
self.name = nil;
self.kcal = nil;
self.fat = nil;
self.carbohydrates = nil;
[super dealloc];
}
#end
NutritionsDB.m:
#import "NutritionsDB.h"
#import "sqlite.h"
#implementation NutritionsDB
static NutritionsDB *_database;
+ (NutritionsDB*)database {
if (_database == nil) {
_database = [[NutritionsDB alloc] init];
}
return _database;
}
- (id)init {
if ((self = [super init])) {
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"Livsmedeldatabas"
ofType:#"sqlite"];
if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
NSLog(#"Failed to open database!");
}
}
return self;
}
- (void)dealloc {
sqlite3_close(_database);
[super dealloc];
}
-(void)setUpDB{
const char *sql_stmt = "CREATE INDEX IF NOT EXISTS name_index on livsmedel(namn)";
char *errMsg;
if (sqlite3_exec(_database, sql_stmt, NULL, NULL, &errMsg) == SQLITE_OK)
{
puts("Index successfully created");
// SQL statement execution succeeded
}
}
-(NSArray*)sqliteInfo:(NSString*)predicateString{
NSMutableArray *retval = [[[NSMutableArray alloc] init] autorelease];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [predicateString cStringUsingEncoding:NSUTF8StringEncoding], -1, &statement, nil)
== SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
char *nameChars = (char *) sqlite3_column_text(statement, 0);
char *kcalchars = (char *) sqlite3_column_text(statement, 1);
char *fatchars = (char *) sqlite3_column_text(statement, 2);
char *carbchars = (char *) sqlite3_column_text(statement, 3);
NSLog(#"\n%s, \n%s, \n%s", kcalchars, fatchars, carbchars);
NSString *name = [[NSString alloc] initWithUTF8String:nameChars];
NSString *kcal = [NSString stringWithFormat:#"%s", kcalchars];
NSString *fat = [NSString stringWithFormat:#"%s", fatchars];
NSString *carb = [NSString stringWithFormat:#"%s", carbchars];
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * kcalNumber = [f numberFromString:kcal];
NSNumber * fatNumber = [f numberFromString:fat];
NSNumber * carbNumber = [f numberFromString:carb];
NSLog(#"\n kcalnum : %#, \n fatnum: %#, \n carbnum : %#", kcalNumber, fatNumber, carbNumber);
[f release];
sqlite *info = [[sqlite alloc] initWithName:name carbs:carbNumber fat:fatNumber kcal:kcalNumber] ;
NSLog(#"%#,%#,%#,%#", name, kcal, fat, carb);
[retval addObject:info];
[name release];
[kcal release];
[fat release];
[carb release];
}
sqlite3_finalize(statement);
}
return retval;
}
#end
Now, In one of my viewcontrollers, I continuously make database calls via the method
-(NSArray*)sqliteInfo:(NSString*)predicateString.
predicateString is a copy of a text which the user enters in a search bar inside the VC.
In addition to the UISearchBar, the VC also holds a UITableView to represent the rows fetched from the databse.
Here is how I update the datasource contents and re-render the the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.nutritionList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"hej");
static NSString *CellIdentifier = #"NutritionIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.font = [UIFont fontWithName:#"Avenir-Medium" size:18.0];
cell.textLabel.text = [(sqlite*)[self.nutritionList objectAtIndex:indexPath.row] name];
return cell;
}
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
[self.nutritionList removeAllObjects];
if (searchText.length < 2) {
;
} else {
NSString *firstChar = [searchText substringWithRange:NSMakeRange(0, 1)];
if([firstChar isEqualToString:#"å"] ||
[firstChar isEqualToString:#"Å"] ||
[firstChar isEqualToString:#"ä"] ||
[firstChar isEqualToString:#"Ä"] ||
[firstChar isEqualToString:#"ö"] ||
[firstChar isEqualToString:#"Ö"]){
NSString *lowerString = [firstChar lowercaseString];
NSString *upperString = [firstChar uppercaseString];
NSString *newSearchText = [searchText stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:lowerString];
NSString *newSearchText_upper = [searchText stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:upperString];
NSString *formatString = [[[[[#"'"stringByAppendingString:newSearchText]stringByAppendingString:#"%'"]
stringByAppendingString:#" OR namn like'"]stringByAppendingString:newSearchText_upper]stringByAppendingString:#"%' ORDER BY namn COLLATE NOCASE"];
NSArray *array = [[NutritionsDB database] sqliteInfo:[NSString stringWithFormat:#"Select * from livsmedel where namn like %#", formatString ]];
NSLog(#"%#",[NSString stringWithFormat:#"Select * from livsmedel where namn like %#", formatString ] );
for (sqlite *info in array) {
[self.nutritionList addObject:info];
}
}else{
NSString *formatString = [[#"'"stringByAppendingString:searchText]stringByAppendingString:#"%' "];
NSArray *array = [[NutritionsDB database] sqliteInfo:[NSString stringWithFormat:#"SELECT * FROM livsmedel WHERE namn LIKE %#", formatString ]];
NSLog(#"%#",[NSString stringWithFormat:#"Select * from livsmedel where namn like %#", formatString ] );
for (sqlite *info in array) {
[self.nutritionList addObject:info];
NSLog(#"carbs %#, fat %#, kcal %#", info.carbohydrates, info.fat, info.kcal);
}
}
}
[self.tableView reloadData];
}
Finally the crash occurs after the numberOfRowsInSection method is called, but before the cellForRowAtIndexPath is called. Somewhere between them.
The console says (lldb), nothing else. The view below is the assembly instructions that indicates where the crash occurs. However, I do not now how to interpret them.
My question: Why does this crash occur?
Thanks for your help.

Show Contact list on table view of iPhone

I have a view controller where I have an add contact button and a table view. On clicking the add contact button a new view controller opens where there are a few textfields and labels and a button(Submit) which adds the textfield data to the database. I want that as I press the Submit button, the table view in the previous controller should contain the name and contact no. of the contact that was submitted. The addContact method is as follws:
-(IBAction)addContact{
sqlite3_stmt *statement;
const char *dbpath = [mDatabasePath UTF8String];
if (sqlite3_open(dbpath, &mDiary) == SQLITE_OK)
{
NSString *insertSQL1=[NSString stringWithFormat:#"INSERT INTO CONTACTS VALUES(\"%#\",\"%#\",\"%#\",\"%#\",\"%#\")", mName.text, mContactno.text,mCemail.text,mClatitude.text,mClongitude.text];
const char *insert_stmt1 = [insertSQL1 UTF8String];
sqlite3_prepare_v2(mDiary, insert_stmt1,
-1, &statement, NULL);
NSString *tempName = [NSString stringWithFormat:#"%#",mName.text];
NSString *tempNo = [NSString stringWithFormat:#"%#",mContactno.text];
tempName = [tempName stringByAppendingString:tempNo];
[phoneContacts addObject:tempName];
tableView.delegate = self;
tableView.dataSource = self;
[tableView reloadData];
if (sqlite3_step(statement) == SQLITE_DONE)
{ mStatus.text=#"Contact added";
mName.text=#"";
mContactno.text=#"";
mCemail.text=#"";
mClatitude.text=#"";
mClongitude.text=#"";
}
else {
mStatus.text = #"Failed to add contact";
}
sqlite3_finalize(statement);
sqlite3_close(mDiary);
}
}
The table view methods are:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.phoneContacts count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [self.phoneContacts objectAtIndex:indexPath.row];
return cell;
}
Nothing is getting shown in the table view. Why?
I've added a method populateContactTable:
-(IBAction)populateContactTable:(id)sender
{
sqlite3_stmt *statement;
const char *dbpath = [mDatabasePath UTF8String];
if (sqlite3_open(dbpath,&mDiary)== SQLITE_OK) {
NSString *selectSQL = [NSString stringWithFormat:#"SELECT * FROM CONTACTS"];
const char *query_stmt = [selectSQL UTF8String];
if (sqlite3_prepare_v2(mDiary,
query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
tempContactName = [[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
tempContactNo = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement,1)];
tempContactName = [tempContactName stringByAppendingString:#" "];
tempContactName = [tempContactName stringByAppendingString:tempContactNo];
[phoneContacts addObject:tempContactName];
tableView.delegate = self;
tableView.dataSource = self;
[tableView reloadData];
// NSLog(#"%#",userName);
// return tempContactName;
}
}
sqlite3_finalize(statement);
}
sqlite3_close(mDiary);
}
this method is called via a button in the root view controller. Still no data from the database is getting shown on the table.
Here's a snap of the storyboard:

Resources