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.
Related
Hi I have built a dictionary application my data base has 78.000 record , so when I trying to search through data base the searching process is not smooth and you feel some delay ! specially when try to type first letter when app lunched . here is my codes , I would be grateful if help me to find a solution :
Searching :
- (void)searchWord:(NSString *)txt{
sqlite3_exec(database, "REINDEX table;", NULL, NULL, NULL);
NSMutableArray *DB_Array = [[NSMutableArray alloc] init];
NSString *dbPath = [[NSString alloc] initWithString: [self getDBPath]];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
// #"SELECT * FROM DIC WHERE NAME != '%#%%' ORDER BY NAME LIMIT 30"
// SELECT * FROM DIC Where Name LIKE '%#%%' order by NAME LIMIT 30
NSString *sql =[NSString stringWithFormat:#"SELECT ID,NAME FROM DIC WHERE NAME LIKE '%#%%' ORDER BY NAME LIMIT 15",txt];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [sql UTF8String] , -1, &compiledStatement, NULL) == SQLITE_OK) {
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSInteger oid = sqlite3_column_int(compiledStatement, 0);
const char* f1 = (const char*)sqlite3_column_text(compiledStatement, 1);
NSString *oName = f1 == NULL ? nil : [[NSString alloc] initWithUTF8String:f1];
// NSLog(#"%#",oName);
const char* f2 = (const char*)sqlite3_column_text(compiledStatement, 2);
NSString *oMean = f2 == NULL ? nil : [[NSString alloc] initWithUTF8String:f2];
const char* f3 = (const char*)sqlite3_column_text(compiledStatement, 3);
NSString *oPron = f3 == NULL ? nil : [[NSString alloc] initWithUTF8String:f3];
NSInteger bm = sqlite3_column_int(compiledStatement, 5);
readerClass = [[Reader alloc]initWithReadDB:oid Name:oName Mean:oMean Pron:oPron bookMark:bm];
[DB_Array addObject:readerClass];
}
}
else {
NSLog(#"Error retrieving data from database.");
}
sqlite3_close(database);
}
else {
NSLog(#"Error: Can't open database!");
NSLog(#" DB Name %#",viewController.dbName);
}
AppDelegate *appDelegateClass = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegateClass.wordList removeAllObjects];
[appDelegateClass.wordList=DB_Array mutableCopy];
[appDelegateClass setCurrentDBPath:[dbPath UTF8String]];
}
TableView :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
appClass = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"%d",appClass.wordList.count);
return appClass.wordList.count;
}
- (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];
}
appClass = (AppDelegate *)[[UIApplication sharedApplication] delegate];
readerClass = (Reader *)[appClass.wordList objectAtIndex:indexPath.row];
cell.textLabel.text = readerClass.Name;
return cell;
}
SearchBar :
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {
if([searchText length] > 0) {
dbClass=[[DB alloc]init];
[dbClass searchWord:searchText];
}else
{
dbClass=[[DB alloc]init];
[dbClass searchWord:#" "];
}
[self.myTable reloadData];
}
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
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
I'm trying to implement the searchBar following steps in this Video
But I got the following exception when I press the searchBar
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't do regex matching on object <Authors: 0x10960c1e0>.'
AuthorsTableViewController.h
#interface AuthorsTableViewController : UITableViewController <UISearchBarDelegate> {
NSMutableArray *authorsArray;
NSMutableArray *resultArray;
QuotesNavController *quotes;
}
#property (nonatomic, strong) IBOutlet UISearchBar *SearchBar;
#property (nonatomic, retain) NSMutableArray *authorsArray;
#property (nonatomic, retain) NSMutableArray *resultArray;
-(sqlite3 *) openDataBase;
-(IBAction)backToQuotes:(id)sender;
#end
AuthorsTableViewController.m
#import "AuthorsTableViewController.h"
#interface AuthorsTableViewController ()
#end
#implementation AuthorsTableViewController
#synthesize authorsArray, resultArray;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self retrieveDataFromSqlite];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(IBAction)backToQuotes:(id)sender{
[self performSegueWithIdentifier:#"backToQuotes" sender:sender];
}
-(sqlite3 *) openDataBase{
sqlite3 *database;
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"SuccessQuotes" ofType:#"sqlite"];
if (sqlite3_open([sqLiteDb UTF8String], &database) != SQLITE_OK) {
NSLog(#"Failed to open database!");
}else{
NSLog(#"database opened!");
}
return database;
}
-(void) retrieveDataFromSqlite{
authorsArray = [[NSMutableArray alloc] init];
sqlite3 *myDatabase = [self openDataBase];
const char *sqlSelect = "SELECT *, COUNT(qu_author) AS count FROM authors JOIN quotes ON _auid = qu_author GROUP BY au_name ORDER BY au_name ASC";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(myDatabase, sqlSelect, -1, &compiledStatement, NULL) == SQLITE_OK) {
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
int author_id = sqlite3_column_int(compiledStatement, 0);
NSString *au_name = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 1)];
NSString *au_picture = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 2)];
int quotes_id = sqlite3_column_int(compiledStatement, 3);
NSString *quotes_content = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 4)];
int quotes_author = sqlite3_column_int(compiledStatement, 5);
NSString *quotes_favorite = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 6)];
int count = sqlite3_column_int(compiledStatement, 7);
Authors *authors = [[Authors alloc] initWithUniqueId:author_id au_name:au_name au_picture:au_picture quotes_id:quotes_id quotes_content:quotes_content quotes_author:quotes_author quotes_author:quotes_author quotes_favorite:quotes_favorite count:count];
[authorsArray addObject:authors];
} // while end
}// prepare end
sqlite3_finalize(compiledStatement);
sqlite3_close(myDatabase);
}
- (void) searchThroughtData {
self.resultArray = nil;
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF like[c] %#",[NSString stringWithFormat:#"%#*",self.SearchBar.text]];
self.resultArray = [[self.authorsArray filteredArrayUsingPredicate:resultPredicate] mutableCopy];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.tableView) {
return [authorsArray count];
} else {
[self searchThroughtData];
return [resultArray count];
}
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
[self searchThroughtData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"authorCell";
AuthorsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[AuthorsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
Authors *temp_items;
if (tableView == self.tableView) {
temp_items = [self.authorsArray objectAtIndex:indexPath.row];
}else{
temp_items = [self.resultArray objectAtIndex:indexPath.row];
}
[cell.authorName setText:[NSString stringWithFormat:#"%#",temp_items.au_name]];
[cell.count setTitle:[NSString stringWithFormat:#"%d",temp_items.count] forState:UIControlStateNormal];
UIImage *theImage = [UIImage imageNamed:temp_items.au_picture];
cell.authorPic.image = theImage;
UIView *customColorView = [[UIView alloc] init];
customColorView.backgroundColor = [UIColor colorWithRed:93/255.0
green:45/255.0
blue:22/255.0
alpha:0.5];
cell.selectedBackgroundView = customColorView;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Authors *temp_items = [self.authorsArray objectAtIndex:indexPath.row];
quotes = [self.storyboard instantiateViewControllerWithIdentifier:#"QuotesNavController"];
quotes.quType = 3;
quotes.authorId = temp_items.author_id;
[self presentModalViewController:quotes animated:YES];
}
#end
I've looked around a lot but have been unable to find an answer for this one...
I have a class in my app that contains Chinese Pinyin pronunciation set up as
pronunciation# [space] pronunciation#
for instance 你好[hello] would be
ni3 hao3
so my question is how can I get NSPredicate to ignore the numbers in the string/class during a search?
ideally I would be able to search:
"nihao"
"ni hao"
etc
and still end up with the same result (你好 ni3 hao3)
I've tried out a few LIKE instances but have failed miserably every time...
Thanks
here's my array, as per request:
-(NSMutableArray *) wordList{
cdh = [[NSMutableArray alloc] initWithCapacity:10];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"cdh.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));
}
const char *sql = "SELECT * FROM MAIN";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}else{
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
Words * word = [[Words alloc] init];
word.head = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,0)];
word.pro = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,1)];
word.def = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,2)];
[cdh addObject:word];
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
return cdh;
}
}
Words.h
#import <Foundation/Foundation.h>
#import "TestViewController.h"
#interface Words : NSObject {
NSString *head;
NSString *pro;
NSString *def;
}
#property(nonatomic, copy) NSString *head;
#property(nonatomic, copy) NSString *pro;
#property(nonatomic, copy) NSString *def;
#end
Words.m
#import "Words.h"
#implementation Words
#synthesize head;
#synthesize pro;
#synthesize def;
- (NSString *)searchableStringValue {
NSCharacterSet *invalidSet = [[NSCharacterSet characterSetWithCharactersInString:#"[]0123456789 "] invertedSet];
NSString *searchString = [[pro componentsSeparatedByCharactersInSet:invalidSet] componentsJoinedByString:#""];
return searchString;
}
#end
TestViewController.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#import "Words.h"
#interface TestViewController : UITableViewController {
NSMutableArray *cdh;
sqlite3 * db;
}
#property(nonatomic,retain) NSMutableArray *cdh;
#property (nonatomic, strong) NSData *myData;
-(NSMutableArray *) wordList;
#end
TestViewController.m (inc. predicate)
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"(head beginswith[c] %#) OR (searchableStringValue beginswith[c] %#)", searchText, searchText];
searchResults = [cdh filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
// Return the number of rows in the section.
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchResults count];
} else {
return [self.cdh count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// int rowCount = indexPath.row;
// Words *word = [self.cdh objectAtIndex:rowCount];
// cell.textLabel.text = word.head;
// cell.detailTextLabel.text = [NSString stringWithFormat:#"%# %#", word.pro, word.def];
// Configure the cell...
Words *word = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
word = [searchResults objectAtIndex:indexPath.row];
} else {
word = [cdh objectAtIndex:indexPath.row];
}
cell.textLabel.text = word.head;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%# %#", word.pro, word.def];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"ShowWordDetails"]) {
NSIndexPath *indexPath = nil;
Words *word = nil;
if (self.searchDisplayController.active) {
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
word = [searchResults objectAtIndex:indexPath.row];
} else {
indexPath = [self.tableView indexPathForSelectedRow];
word = [cdh objectAtIndex:indexPath.row];
}
DetailsViewController *destViewController = segue.destinationViewController;
destViewController.word = word;
}
}
Your strings are contained in a Words class. This gives you a perfect opportunity to create additional methods to help out with processing the strings it holds (i.e. you don't need to try doing everything in the predicate).
For instance, consider adding a method which returns:
- (NSString *)searchableStringValue
this method would take the string that you are currently trying to search and mutate it to remove the brackets, numbers, spaces. This can most easily be achieved with:
NSCharacterSet *invalidSet = [[NSCharacterSet characterSetWithCharactersInString:#"[]0123456789 "] invertedSet];
NSString *searchString = [[##XXX## componentsSeparatedByCharactersInSet:invalidSet] componentsJoinedByString:#""];
where ##XXX## is the string that you are currently trying to search.
Now, your predicate should use searchableStringValue, instead of the string that you are currently trying to search.