My Search Bar works in console but in the simulator doesn't work and i don't know why.
I have tried with many codes but nothing works. I'm looking for restaurant names in my tableview but when i type nothing happen, everything stays equal in the simulator.
This is my code:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
if([searchText length] == 0){
[jsonObject2 removeAllObjects];
[jsonObject2 addObjectsFromArray:jsonObject];
}else{
[jsonObject2 removeAllObjects];
for(NSDictionary *dictionary in jsonObject)
{
NSObject *ob = [dictionary objectForKey:#"nombres"];
if([ob isKindOfClass: [NSString class]])
{
NSString*string=[ob description];
NSRange range = [string rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
[jsonObject2 addObject:ob];
NSLog(#"%#",jsonObject2);
}
}
}
}
[myTableView reloadData];
}
-(void)searchBarSearchButtonClicked:(UISearchBar *)asearchBar{
[searchBar resignFirstResponder];
}
There may be two reasons for this issue
You are using jsonObject as your data source of table view. If so use jsonObject2.
If first case is wrong then may be you should log your jsonObject2 after all search component are added in that. And fix that in case it doesn't string objects in it.
I found my problem and i add this code to search textDidChange method:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
if([searchText length] == 0){
[jsonObject2 removeAllObjects];
[jsonObject2 addObjectsFromArray:jsonObject];
//NSLog(#"%#",jsonObject2);
}else{
[jsonObject2 removeAllObjects];
for(NSDictionary *dictionary in jsonObject)
{
NSString*string=[dictionary objectForKey:#"nombres"];
NSRange range=[string rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
[jsonObject2 addObject:dictionary];
NSLog(#"%#",jsonObject2);
}
}
}
[myTableView reloadData];
}
First check UITableView and UISearchBar are add properly or not ??? ... and then Take Two NSMutableArray and add one array to another array in ViewDidLoad method such like,
self.listOfTemArray = [[NSMutableArray alloc] init]; // array no - 1
self.ItemOfMainArray = [[NSMutableArray alloc] initWithObjects:#"YorArrayList", nil]; // array no - 2
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray]; // add 2array to 1 array
And Write following Methos of code
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText
{
NSString *name = #"";
NSString *firstLetter = #"";
if (self.listOfTemArray.count > 0)
[self.listOfTemArray removeAllObjects];
if ([searchText length] > 0)
{
for (int i = 0; i < [self.ItemOfMainArray count] ; i = i+1)
{
name = [self.ItemOfMainArray objectAtIndex:i];
if (name.length >= searchText.length)
{
firstLetter = [name substringWithRange:NSMakeRange(0, [searchText length])];
//NSLog(#"%#",firstLetter);
if( [firstLetter caseInsensitiveCompare:searchText] == NSOrderedSame )
{
// strings are equal except for possibly case
[self.listOfTemArray addObject: [self.ItemOfMainArray objectAtIndex:i]];
NSLog(#"=========> %#",self.listOfTemArray);
}
}
}
}
else
{
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray ];
}
[self.tblView reloadData];
}
And Write in cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Foobar"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Foobar"];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.textLabel.textColor = [UIColor blackColor];
}
cell.textLabel.text = [self.listOfTemArray objectAtIndex: indexPath.row];
return cell;
}
This code might helpful for you...thanks :)
Related
I am trying to do a search in a UITableview. I have implemented the UISearchDisplayDelegate, UISearchBarDelegate method at the correct way. This is how my cellForRowAtIndexPath looks like.
- (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];
}
if (tableView == self.searchDisplayController.searchResultsTableView){
Contact *contact = [self.filteredListContent objectAtIndex:indexPath.row];
NSString *text = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
NSLog(#"CellForRowAtIndexPath contact text is %#",text);
cell.textLabel.text = text;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}else{
NSString *alphabet = [firstIndex objectAtIndex:[indexPath section]];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF.name beginswith[c] %#",alphabet];
NSArray *contacts = [listContent filteredArrayUsingPredicate:predicate];
Contact *contact = [contacts objectAtIndex:indexPath.row];
NSString *text = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
cell.textLabel.text = text;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
return cell;
}
And this is my filterContentForSearchText method
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
[self.filteredListContent removeAllObjects]; // First clear the filtered array.
for (Contact *contact in listContent)
{
NSString *searchString = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
NSRange range = [searchString rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
[self.filteredListContent addObject:contact];
[self.searchDisplayController.searchResultsTableView reloadData];
}
}
}
The strange thing is. In my cellForRowAtIndexPath it returns me the correct data. But the tableview itselfs keeps given me the NO RESULTS label.
Any help with this?
Follow this tutorial how-to-add-search-bar-uitableview ..
Just see the method cellForRowAtIndexPath: in which how to set the search array when user searched record from UISearchBar...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"RecipeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [searchResults objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [recipes objectAtIndex:indexPath.row];
}
return cell;
}
Use an array to show data in table(showDataArray)
Use an array to store all input values(dataArray)
Use showDataArray to populate your table always
In the searchfield when charecter range changes call a method to filter the data using predicate from dataArray
Save the value to showDataArray
Call for table reloadData
First add UISearchBar on top of UITabelView documentation
And then Take Two NSMutableArray and add one array to another array in ViewDidLoad method such like,
self.listOfTemArray = [[NSMutableArray alloc] init]; // array no - 1
self.ItemOfMainArray = [[NSMutableArray alloc] initWithObjects:#"YorArrayList", nil]; // array no - 2
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray]; // add 2array to 1 array
And Write following delegate Method of UISearchBar
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText
{
NSString *name = #"";
NSString *firstLetter = #"";
if (self.listOfTemArray.count > 0)
[self.listOfTemArray removeAllObjects];
if ([searchText length] > 0)
{
for (int i = 0; i < [self.ItemOfMainArray count] ; i = i+1)
{
name = [self.ItemOfMainArray objectAtIndex:i];
if (name.length >= searchText.length)
{
firstLetter = [name substringWithRange:NSMakeRange(0, [searchText length])];
//NSLog(#"%#",firstLetter);
if( [firstLetter caseInsensitiveCompare:searchText] == NSOrderedSame )
{
// strings are equal except for possibly case
[self.listOfTemArray addObject: [self.ItemOfMainArray objectAtIndex:i]];
NSLog(#"=========> %#",self.listOfTemArray);
}
}
}
}
else
{
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray ];
}
[self.tblView reloadData];
}
And Write in cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Foobar"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Foobar"];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.textLabel.textColor = [UIColor blackColor];
}
cell.textLabel.text = [self.listOfTemArray objectAtIndex: indexPath.row];
return cell;
}
I'm accomplishing the concept of AutoCompleteTextView in iPhone similar to we find when we go for safari..I'm doing it with the help of UITableView.But Im getting error "Program received signal SIGABRT" Could not understand where I m going wrong ..?
My array looks like this :
(
{
Name = "John";
},
{
Name = "Williams ";
},
{
Name = "Michael ";
},
{
Name = "Hillary ";
},
{
Name = "Jennifer ";
},
)
so I have to get the values of Name in cells of tableView..
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {
[autocompleteUrls removeAllObjects];
for(int i=0;i<[arr2 count];i++)
{
for(NSString *curString in [[arr2 objectAtIndex:i] valueForKey:#"Name"]) //error :Program recieved signal SIGABRT
{
NSRange substringRange = [curString rangeOfString:substring];
if (substringRange.location == 0)
{
[autocompleteUrls addObject:curString];
}
}
}
[autocompleteTableView reloadData];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if( textField == txtcity)
{
[txtcity resignFirstResponder];
autocompleteTableView.hidden = NO;
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
return YES;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
return autocompleteUrls.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
static NSString *AutoCompleteRowIdentifier = #"AutoCompleteRowIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:AutoCompleteRowIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AutoCompleteRowIdentifier] autorelease];
}
cell.textLabel.text = [autocompleteUrls objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
txtcity.text = selectedCell.textLabel.text;
}
I m getting error at this line : for(NSString *curString in [[arr2 objectAtIndex:i] valueForKey:#"Name"])
Where I m going wrong..? Any help would be appreciated..
Try:
for(NSString *curString in arr2)
or
for(int i=0;i<[arr2 count];i++)
{
NSString *curString = [[arr2 objectAtIndex:i] valueForKey:#"Name"]
curString = [curString lowercaseString];
substring = [substring lowercaseString];
if ([curString rangeOfString:substring].location == NSNotFound)
{}
else
{
[autocompleteUrls addObject:curString]
}
}
[[arr2 objectAtIndex:i] valueForKey:#"Name"] will return a string (a name), not an array. Therefore you don't need that for loop.
Just assign the name you're returning to the variable:
for(int i=0;i<[arr2 count];i++)
{
NSString *curString = [[arr2 objectAtIndex:i] valueForKey:#"Name"]
NSRange substringRange = [curString rangeOfString:substring];
if (substringRange.location == 0)
{
[autocompleteUrls addObject:curString];
}
}
I have a textfield where the user enters the name.Now when a letter is typed in the textfield,let's say "T",then how can I get suggestions of names from contact list in iphone with respect to that letter entered.
Also I need to display the appropriate number corresponding to the name entered.
I have gone through apple documentation,
Can anyone please help me out with valuable suggestions or sample code snippet:
Thanks in advance :)
EDIT
I was able to view the contacts in log(console),as I wrote the code suggested by Mr.Anil Kothari in viewDidLoad method
As suggested by Mr.Anil Kothari,I have implemented the search bar code for textfield delegate methods as follows:
- (void)textFieldDidBeginEditing:(UITextField *)atextField
{
if(searching)
return;
searching = YES;
}
- (void) searchTableView
{
textField = [self.fields objectAtIndex:0];
NSString *searchText = textField.text;
for (UIView *subview in searchBar.subviews)
{
if ([subview isKindOfClass:[UITextField class]])
{
textField = (UITextField *)subview;
break;
}
}
textField.enablesReturnKeyAutomatically = NO;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
//searchArray contains matched names of friends with the searching string
for (NSString *sTemp in contactList)
{
txtToSearch =[[NSString alloc] initWithString:[sTemp substringWithRange:NSMakeRange(0,[searchText length])]];
textField = [self.fields objectAtIndex:0];
txtToSearch = textField.text;
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[copyListOfItems addObject:sTemp];
}
[searchArray release];
searchArray = nil;
}
-(BOOL)textField:(UITextField *)atextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
[copyListOfItems removeAllObjects];
if([string length] > 0)
{
searching = YES;
[self searchTableView];
}
else
{
searching = NO;
}
}
But still not working :(
Check the Code I have already done in some application this kind of stuff:-
- (void)viewDidLoad {
[super viewDidLoad];
self.tblSearchList.tableHeaderView = searchBar;
contactList=[[NSMutableArray alloc]init];
copyListOfItems=[[NSMutableArray alloc]init];
ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i );
NSString *contactName =[[NSString alloc] initWithString:(NSString *)ABRecordCopyValue(ref,kABPersonFirstNameProperty)];
NSLog(#"% # ",contactName);
[contactList addObject:contactName];
[contactName release];
}
}
searchBar Delegate's
- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar {
if(searching)
return;
searching = YES;
}
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {
[copyListOfItems removeAllObjects];
if([searchText length] > 0) {
searching = YES;
[self searchTableView];
}
else {
searching = NO;
}
[self.tblSearchList reloadData];
}
- (void) searchTableView {
NSString *searchText = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
//searchArray contains matched names of friends with the searching string
for (NSString *sTemp in contactList)
{
NSString *txtToSearch =[[NSString alloc] initWithString:[sTemp substringWithRange:NSMakeRange(0,[searchText length])]];
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[copyListOfItems addObject:sTemp];
}
[searchArray release];
searchArray = nil;
}
- (void) doneSearching_Clicked:(id)sender {
searchBar.text = #"";
[searchBar resignFirstResponder];
searching = NO;
[self.tblSearchList reloadData];
}
tableView Delegate's
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (searching)
return [copyListOfItems count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if(searching)
return #"Search Results";
return #"";
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
if(searching)
cell.textLabel.text = [copyListOfItems objectAtIndex:indexPath.row];
return cell;
}
fell free to ask for any further queries..
You should use UISearchBar, implement the delegate method:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
Take the letter\s from searchText and fetch the contacts using ABAddressBookRef then update the SearchDisplayController accordingly..
hope this helps a little
i have a SQL file where 5 different type of data is stored. I am adding this data in a dictionary specified with keys. and then i am adding this dictionary to tableData array as a dataSource for table and searchBar. But it is not searching anything.
adding code below
- (void)viewDidLoad {
[super viewDidLoad];
dataSource =[[NSMutableArray alloc] init];
tableData = [[NSMutableArray alloc]init];
searchedData = [[NSMutableArray alloc]init];
NSString *query = [NSString stringWithFormat:#"SELECT * FROM Vegetables"];
SQLite *sqlObj1 = [[SQLite alloc] initWithSQLFile:#"ShoppersWorld.sqlite"];
[sqlObj1 openDb];
[sqlObj1 readDb:query];
// [query release];
for (int i=0; i<[dataSource count]; i++) {
NSLog(#"data:%#",[dataSource objectAtIndex:i]);
}
while ([sqlObj1 hasNextRow])
{
NSString *name=[sqlObj1 getColumn:1 type:#"text"];
NSString *price=[sqlObj1 getColumn:2 type:#"text"];
NSString *quantity=[sqlObj1 getColumn:3 type:#"text"];
NSString *unit=[sqlObj1 getColumn:4 type:#"text"];
NSString *total=[sqlObj1 getColumn:5 type:#"text"];
dict = [[NSMutableDictionary alloc] initWithObjectsAndKeys: name,#"nameOfVegetables",
price,#"priceOfVegetables",
quantity,#"quantityOfVegetables",
unit,#"unitOfVegetables",
total,#"totalPriceOfVegetables",nil];
//NSLog(#"results:%# %#",dict);
[dataSource addObject:dict];
}
[tableData addObjectsFromArray:dataSource];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
// Configure the cell.
else {
cell.productLbl.text= [NSString stringWithFormat:#"%#",[[tableData objectAtIndex:indexPath.row]objectForKey:#"nameOfVegetables"] ];
cell.bPriceLbl.text = [NSString stringWithFormat:#"Rs %d/Kg",
[[[tableData objectAtIndex:indexPath.row] objectForKey:#"priceOfVegetables"] intValue]];
cell.qtyLbl.text = [NSString stringWithFormat:#"QTY: %# %#",[[tableData objectAtIndex:indexPath.row]
objectForKey:#"quantityOfVegetables"],[[tableData objectAtIndex:indexPath.row] objectForKey:#"unitOfVegetables"]] ;
cell.tPriceLbl.text = [NSString stringWithFormat:#"TOTAL: %#",[[tableData objectAtIndex:indexPath.row]
objectForKey:#"totalPriceOfVegetables"]];
}
return cell;
}
#pragma search operations
- (IBAction)search:(id)sender{
sBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,40,320,30)];
sBar.delegate = self;
[self.view addSubview:sBar];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
// only show the status bar’s cancel button while in edit mode
[sBar setShowsCancelButton:YES animated:YES];
sBar.autocorrectionType = UITextAutocorrectionTypeNo;
// flush the previous search content
[tableData removeAllObjects];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
[sBar setShowsCancelButton:NO animated:YES];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
[tableData removeAllObjects];// remove all data that belongs to previous search
if([searchText isEqualToString:#""] || searchText==nil){
[tableview reloadData];
return;
}
NSInteger counter = 0;
for(NSString *name in dataSource)
for (int i = 0; i < [dataSource count]; i++)
{
NSMutableDictionary *temp = (NSMutableDictionary*) [dataSource objectAtIndex:i];
NSString *name = [NSString stringWithFormat:#"%#", [temp valueForKey:#"nameOfVegetables"]];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSRange r = [name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound)
{
if(r.location== 0)//that is we are checking only the start of the names.
{
[tableData addObject:name];
}
}
counter++;
[pool release];
}
[tableview reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
sBar.hidden= YES;
// if a valid search was entered but the user wanted to cancel, bring back the main list content
[tableData removeAllObjects];
[tableData addObjectsFromArray:dataSource];
#try{
[tableview reloadData];
}
#catch(NSException *e){
}
[sBar resignFirstResponder];
sBar.text = #"";
}
In search delegate methods you manipulate not with searchedData but tableData array. As these name suggest, array searchedData is supposed to store filtered data.
By the way, your approach to use sqlite for data source and absorbing all database into array is wrong. In cellForRowAtIndexPath read from sqlite database only data you need at the moment.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// load from sqlite only data for this cell.
// Use searchBar.text with sqlite's LIKE to filter data from database
NSUInteger row = [indexPath row];
static NSString *CellIdentifier = #"SignsCellIdentifier";
UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSString *sql = [NSString stringWithFormat:#"SELECT fieldNameFromTable FROM TableName WHERE FieldToLookForIn LIKE \"%%%#%%\" LIMIT 1 OFFSET %u", searchBar.text ? searchBar.text : #"", row];
sqlite3_stmt *stmt;
int res = sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt, NULL);
if (res != SQLITE_OK) {
NSLog(#"sqlite3_prepare_v2() failed"];
return nil;
}
if (sqlite3_step(stmt) == SQLITE_ROW) {
const unsigned char *name = sqlite3_column_text(stmt, 0);
cell.text = [NSString stringWithUTF8String:(const char*)name];
}
sqlite3_finalize(stmt);
return cell;
}
How to apply search in this approach? In textDidChange do nothing but call [tableView reloadData]. And in cellForRowAtIndexPath load data with sqlite LIKE using searchBar.text as search term. So reloadData will load only filtered records. searchBarSearchButtonClicked will call only resignFirstResponder of it's caller, removing keyboard off screen. It doesn't need to do anything more because search is already done. searchBarCancelButtonClicked will set text property of it's caller to nil, call reload data and again call resignFirstResponder.
- (void)searchBarCancelButtonClicked:(UISearchBar *)s {
s.text = nil;
[tableView reloadData];
[s resignFirstResponder];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)s {
// search is already done
[s resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[tableView reloadData];
}
numberOfRowsInSection should also request db with the same SELECT as in cellForRowAtIndexPath, but with SELECT COUNT. Writing this method will be your homework)
I need to sort by value instead of Key, I think....
Heres where I populate my arrarys
const char *sql = "select cid, category from Categories ORDER BY category DESC";
sqlite3_stmt *statementTMP;
int error_code = sqlite3_prepare_v2(database, sql, -1, &statementTMP, NULL);
if(error_code == SQLITE_OK) {
while(sqlite3_step(statementTMP) == SQLITE_ROW)
{
int cid = sqlite3_column_int(statementTMP, 0);
NSString *category = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statementTMP, 1)];
NSArray *arr=[[NSArray alloc]initWithObjects:category,nil];
[arrayTmp setObject:arr forKey:[NSString stringWithFormat:#"%i",cid]];
[self.cidList addObject:[NSString stringWithFormat:#"%i",cid]];
[category release];
[arr release];
}
}
sqlite3_finalize(statementTMP);
sqlite3_close(database);
self.allCategories = arrayTmp;
[arrayTmp release];
Heres the method where the arrays are re-sorted.
- (void)resetSearch {
NSMutableDictionary *allCategoriesCopy = [self.allCategories mutableDeepCopy];
self.Categories = allCategoriesCopy;
[allCategoriesCopy release];
NSMutableArray *keyArray = [[NSMutableArray alloc] init];
[keyArray addObject:UITableViewIndexSearch];
[keyArray addObjectsFromArray:[[self.allCategories allKeys]
sortedArrayUsingSelector:#selector(compare:)]];
self.keys = keyArray;
[keyArray release];
}
This is a problem i've had for some time, last time I looked at this I could find an altervative to sortedArrayUsingSelector compare?
EDIT
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [Categories objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
SectionsTableIdentifier ];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier: SectionsTableIdentifier ] autorelease];
}
cell.textLabel.text = [nameSection objectAtIndex:row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [Categories objectForKey:key];
NSLog(#"the selected cid is = %i",[key intValue]);
selectButton.enabled = YES;
}
Anyone?
Your obviously attempting to construct an array for use in the -[UITableviewDatasource sectionIndexTitlesForTableView:]. As such, you need an array that looks like this (pseudo-code):
[UITableViewIndexSearch, 0_sectionTitle, 1_sectionTitle, 2_sectionTitle, ...]
I think your immediate problem is that you try to add the UITableViewIndexSearch string constant to the array before you sort which makes it impossible for it end up as the first element unless all your other elements sort below U.
The fix is simple, just add the constant after the sort. You can clean the code up while you're at it:
NSMutableArray *secIdx=[NSMutableArray arrayWithCapacity:[[self.allCategories allKeys] count]];
[secIdx addObjectsFromArray:[self.allCategories allKeys]];
[secIdx sortUsingSelector:#selector(compare:)];
[secIdx insertObject:UITableViewIndexSearch atIndex:0];
self.keys=secIdx;
Note that secIdx is autoreleased so you don't have to release it.
Aside from this problem, your code has a lot of unnecessary/dangerous elements that will make your app fragile and hard to maintain.
You are using a lot of init for objects that you could use autoreleased convenience methods for. The 'init`s poise the risk of memory leaks but give you no advantage.
You need to wrap scalar values in objects so they can be easily managed in collections.
You are using an unnecessary array.
You can rewrite the first block like so:
const char *sql = "select cid, category from Categories ORDER BY category DESC";
sqlite3_stmt *statementTMP;
int error_code = sqlite3_prepare_v2(database, sql, -1, &statementTMP, NULL);
if(error_code == SQLITE_OK) {
NSNumber *cidNum; //... move variable declerations outside of loop
NSString *category; //.. so they are not continously recreated
[self.allCategories removeAllObjects]; //... clears the mutable dictionary instead of replacing it
while(sqlite3_step(statementTMP) == SQLITE_ROW){
cidNum=[NSNumber numberWithInt:(sqlite3_column_int(statementTMP, 0))];
category=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statementTMP, 1)];
//... adding the autoreleased category and cidNum to array/dictionary automatically retains them
[self.allCategories addObject:category forKey:cidNum];
[self.cidList addObject:cidNum];
//[category release]; ... no longer needed
//[arr release]; ... no longer needed
}
}
sqlite3_finalize(statementTMP);
sqlite3_close(database);
//self.allCategories = arrayTmp; ... no longer needed
//[arrayTmp release]; ... no longer needed
Use -sortedArrayUsingComparator: (or -sortedArrayUsingFunction:context: if you can't use blocks). Example:
NSDictionary *categories = [self allCategories];
NSArray *keysSortedByValue = [[categories allKeys] sortedArrayUsingComparator:
^(id left, id right) {
id lval = [categories objectForKey:left];
id rval = [categories objectForKey:right];
return [lval compare:rval];
}];
You could make a small model class Category and implement compare inside of it, then sort an array of those objects using that compare:.
Here's some info - How to sort an NSMutableArray with custom objects in it?
Perhaps you're looking for NSSortDescriptor (and the corresponding sort method, -[NSArray sortedArrayUsingDescriptors]) and friends?
If I understood correctly then what you wish to do to get categories from database & display it on a tableView with alphabetical sorting, index on right & search bar on top. Ideally, you would like to display the Contacts application kind of a view. If that's correct, use below code for fetching items from DB & rebuilding (or resetting) it -
const char *sql = "select cid, category from Categories ORDER BY category DESC";
sqlite3_stmt *statementTMP;
NSMutableArray *arrayTmp = [[NSMutableArray alloc] init];
int error_code = sqlite3_prepare_v2(database, sql, -1, &statementTMP, NULL);
if(error_code == SQLITE_OK) {
while(sqlite3_step(statementTMP) == SQLITE_ROW) {
int cid = sqlite3_column_int(statementTMP, 0);
NSString *category = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statementTMP, 1)];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:category forKey:#"Category"];
[dict setObject:[NSNumber numberWithInt:cid] forKey:#"CID"];
[arrayTmp addObject:dict];
[dict release];
[category release];
}
}
sqlite3_finalize(statementTMP);
sqlite3_close(database);
self.allCategories = arrayTmp;
[arrayTmp release];
And then rebuild the items using this function -
- (void)rebuildItems {
NSMutableDictionary *map = [NSMutableDictionary dictionary];
for (int i = 0; i < allCategories.count; i++) {
NSString *name = [[allCategories objectAtIndex:i] objectForKey:#"Category"];
NSString *letter = [name substringToIndex:1];
letter = [letter uppercaseString];
if (isdigit([letter characterAtIndex:0]))
letter = #"#";
NSMutableArray *section = [map objectForKey:letter];
if (!section) {
section = [NSMutableArray array];
[map setObject:section forKey:letter];
}
[section addObject:[allCategories objectAtIndex:i]];
}
[_items release];
_items = [[NSMutableArray alloc] init];
[_sections release];
_sections = [[NSMutableArray alloc] init];
NSArray* letters = [map.allKeys sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
for (NSString* letter in letters) {
NSArray* items = [map objectForKey:letter];
[_sections addObject:letter];
[_items addObject:items];
}
}
Now, displaying items in tableView, use below methods -
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView {
if (_sections.count)
return _sections.count;
else
return 1;
}
- (NSInteger)tableView:(UITableView*)tableView sectionForSectionIndexTitle:(NSString *)title
atIndex:(NSInteger)index {
if (tableView.tableHeaderView) {
if (index == 0) {
[tableView scrollRectToVisible:tableView.tableHeaderView.bounds animated:NO];
return -1;
}
}
NSString* letter = [title substringToIndex:1];
NSInteger sectionCount = [tableView numberOfSections];
for (NSInteger i = 0; i < sectionCount; i++) {
NSString* section = [tableView.dataSource tableView:tableView titleForHeaderInSection:i];
if ([section hasPrefix:letter]) {
return i;
}
}
if (index >= sectionCount) {
return sectionCount-1;
} else {
return index;
}
}
- (NSArray*)lettersForSectionsWithSearch:(BOOL)withSearch withCount:(BOOL)withCount {
if (isSearching)
return nil;
if (_sections.count) {
NSMutableArray* titles = [NSMutableArray array];
if (withSearch) {
[titles addObject:UITableViewIndexSearch];
}
for (NSString* label in _sections) {
if (label.length) {
NSString* letter = [label substringToIndex:1];
[titles addObject:letter];
}
}
if (withCount) {
[titles addObject:#"#"];
}
return titles;
} else {
return nil;
}
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [self lettersForSectionsWithSearch:YES withCount:NO];
}
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
if (_sections.count) {
NSArray* items = [_items objectAtIndex:section];
return items.count;
} else {
return _items.count;
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (_sections.count)
return [_sections objectAtIndex:section];
return nil;
}
- (id)tableView:(UITableView *)tableView objectForRowAtIndexPath:(NSIndexPath *)indexPath {
if (_sections.count) {
NSArray *section = [_items objectAtIndex:indexPath.section];
return [section objectAtIndex:indexPath.row];
} else {
return [_items objectAtIndex:indexPath.row];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Create your UITableViewCell.
// Configure the cell.
NSDictionary *dict = [self tableView:tableView objectForRowAtIndexPath:indexPath];
cell.textLabel.text = [dict objectForKey:#"Category"];
cell.detailTextLabel.text = [NSString stringWithFormat:%d, [[dict objectForKey:#"CID"] intValue]];
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (isSearching)
return nil;
NSString *title = #"";
if (_sections.count) {
title = [[_sections objectAtIndex:section] substringToIndex:1];
} else {
return nil;
}
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 20)];
view.backgroundColor = [UIColor colorWithRed:(58/255.0) green:(27/255.0) blue:(6/255.0) alpha:1.0];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 1, 50, 18)];
label.textColor = [UIColor whiteColor];
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:17.0];
label.text = title;
[view addSubview:label];
[label release];
return [view autorelease];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *dict = [self tableView:tableView objectForRowAtIndexPath:indexPath];
NSLog(#"selected row id:%d, name:%#", [dict objectForKey:#"Category"], [[dict objectForKey:#"CID"] intValue]);
}
The rest part is implementing the UISearchBarDelegate and implementing searching of tableView which can be done using below code:
- (void)searchBar:(UISearchBar *)searchbar textDidChange:(NSString *)searchText {
[_sections removeAllObjects];
[_items removeAllObjects];
if([searchText isEqualToString:#""] || searchText == nil) {
[self rebuildItems];
return;
}
NSInteger counter = 0;
for(NSDictionary *dict in allCategories) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRange r = [[dict objectForKey:#"Category"] rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound) {
if(r.location == 0) {
[_items addObject:dict];
}
}
counter++;
[pool release];
}
[contactList reloadData];
}
Hope this is what you're looking for.
On your sorting function u should try this:
NSArray *cntxt; //im not sure this is the correct type that ur using on keyArray
[keyArray addObjectsFromArray:[self.allCategories allKeys]];
[keyArray sortUsingFunction:compareFunction context:cntxt];
And the compare function you modify to your needs
NSInteger compareFunction(id x, id y, void *context) {
//NSArray *ctxt = context;
NSArray *c1 = x;
NSArray *c2 = y;
if ([c1 value] < [c2 value])
return NSOrderedDescending;
else if ([c1 value] > [c2 value])
return NSOrderedAscending;
else
return NSOrderedSame;
}
Edit: After reading your comments and after relooking at your code, it seems like that your keyArray as objects of the type NSString, so you should change:
NSInteger compareFunction(id x, id y, void *context) {
//NSString *ctxt = context;
NSString *c1 = x;
NSString *c2 = y;
NSComparisonResult result;
result = [c1 compare:c2];
if (result<0)
return NSOrderedAscending;
else if (result>0)
return NSOrderedDescending;
else
return NSOrderedSame;
}