I am using xcode 5 and want to search a tableView data. I used "Search Bar & Search Display Controller" for "searching", "CustomCell" for "tableCell" and all the data are parsing from a remote server by NSXMLParsing. All data are showing with their corresponding image without any problem but some how my search option doesn't work properly. I do the same code for a single array searsing and it was working. But here it isn't. At the time of searching it is crashed. Here is my code:
-(void)loadData
{
countryParser = [[CountryParser alloc] loadXMLByURL:#"http://www.avowstudio.com/iOS/PartProject/iOS7/XMLParsingWithCustomeCell/XMLFiles/XMLParsingWithCustomCell.xml"];
countryArray = [countryParser countryArray];
displayItems = [[NSMutableArray alloc] initWithArray:countryArray];
[self.countryTableView reloadData];
[activityIndicator stopAnimating];
[self loadArray];
}
-(void) loadArray
{
CountryInfo *currentCountryOne = [[CountryInfo alloc] init];
totalArray = [[NSMutableArray alloc] init];
for (int i=0; i < [countryArray count]; i++)
{
currentCountryOne = [countryArray objectAtIndex:i];
[totalArray addObject:currentCountryOne.countryName];
}
}
-(void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if ([searchText length] == 0)
{
[displayItems removeAllObjects];
[displayItems addObjectsFromArray:countryArray];
}
else
{
[displayItems removeAllObjects];
displayItems = [[NSMutableArray alloc] init];
for (NSString *string in totalArray)
{
NSRange stringRang = [string rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (stringRang.location != NSNotFound)
{
[displayItems addObject:string];
}
}
}
[self.countryTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [displayItems count];
}
// This method is kept the "tableRow height" after "done searching"
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
tableView.rowHeight = 100;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CountryCustomCell *Cell = [self.countryTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!Cell)
{
Cell = [[CountryCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
currentCountry = [displayItems objectAtIndex:indexPath.row];
Cell.ContinentLabel.text = currentCountry.continent;
Cell.CountryNameLabel.text = currentCountry.countryName;
Cell.CapitalLabel.text = currentCountry.capital;
imageQueueCountryFlag = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(imageQueueCountryFlag, ^
{
UIImage *imageCountryFlag = [UIImage imageWithData:[NSData dataWithContentsOfURL: [NSURL URLWithString:[currentCountry countryFlag]]]];
dispatch_async(dispatch_get_main_queue(), ^
{
Cell.CountryFlagImageView.image = imageCountryFlag;
[Cell setNeedsLayout];
});
});
return Cell;
}
I don't want to use two Array in "numberOfRowsInSection" & "cellForRowAtIndexPath" with flag or some thing like that, to avoid more coding. If any one familiar with it please share that here. A lot of thanks in advanced.
I think you are added objects of CountryInfo in the [countryParser countryArray]. In your loadArray method, you just initializing a blank object currentCountryOne and each time the for loop executes, trying to add a blank object's property into totalArray. Please make changes as below:
-(void) loadArray
{
totalArray = countryArray;
}
-(void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if ([searchText length] == 0)
{
[displayItems removeAllObjects];
[displayItems addObjectsFromArray:countryArray];
}
else
{
[displayItems removeAllObjects];
displayItems = [[NSMutableArray alloc] init];
for (CountryInfo *country in totalArray)
{
NSRange stringRang = [country.countryName rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (stringRang.location != NSNotFound)
{
[displayItems addObject:country];
}
}
}
[self.countryTableView reloadData];
}
Instead of adding string to displayItems add the objects containing information about country.
[displayItems addObject:string];
Here you are adding only the countryName to displayItems but while calling cellForRowAtIndexPath: you are asking for its continent,country name and capital which is not present in the array (displayItems) when you reload table after searching.
Exactly which error did you get when it crashed?
It seems to be that when you add an object to your displayItems array. You just add the string object, not the country object.
Your currentCountry is not a country object just the string.
So, in your code enter:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
When you try to parse, it cannot reach:
continent
countryName
capital
Be careful when you search a detailed object.
when you search you add strings to display items not CountryInfo objects so when cellforrow atindexpath gets called again it has to crash
Related
I have created an app where I am using google firebase for backend and Objective-C for front-end.
It successfully storing and displaying data on UITableView.
Now, I am trying to add Search Bar above the table view and tried many examples from the internet but most of them are outdated.
Can anyone please help me with, how I can add search bar above the table view in Objective-C for iOS 9 or later?
Also, How to filter data when we type in the search bar?
Thanks Heaps
Declare in .h file:
BOOL isFiltered;
NSMutableArray *arrsearchresult ,*arrsearchname;
NSMutableArray *arrfullname;
#property (strong, nonatomic) IBOutlet UITableView *tblAppoinment;
Declare in .m file:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
/*if (tableView == self.searchDisplayController.searchResultsTableView) {
return [arrsearchresult count];
} else {
return [arrfullname count];
}*/
if(isFiltered)
{
return [arrsearchresult count];
}
return [arrfullname count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
AppoinmentTableViewCell *cell = (AppoinmentTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"AppoinmentTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
if(isFiltered)
{
cell.lblFullname.text = [arrsearchresult objectAtIndex:indexPath.row];
}
}
if(isFiltered)
{
cell.lblFullname.text = [arrsearchname objectAtIndex:indexPath.row];
}
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
isFiltered = YES;
}
- (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if(searchText.length==0)
{
isFiltered=NO;
}
else
{
isFiltered=YES;
arrsearchresult=[[NSMutableArray alloc]init];
arrsearchdate=[[NSMutableArray alloc]init];
arrsearchname=[[NSMutableArray alloc]init];
for ( NSString * str in arrfullname)
{
NSRange stringRange = [str rangeOfString:searchText options:NSCaseInsensitiveSearch];
NSInteger index;
if(stringRange.location != NSNotFound)
{
[arrsearchresult addObject:str];
index = [arrfullname indexOfObject:str];
[arrsearchdate addObject:[arrleadCreatedDate objectAtIndex:index]];
[arrsearchname addObject:str];
}
}
}
[self.tblAppoinment reloadData];
}
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
[self.tblAppoinment resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
isFiltered=NO;
[self.tblAppoinment reloadData];
}
Though you are talking about search bar. but according to your requirement, it's better to use Search Controller than search bar standalone. Because there are many delegates method you will find along with these.So you don't have to take headache for extra effort.
This code is for filter array.
- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:
(NSRange)range replacementText:(NSString *)text
{
NSArray *resultarray;
NSString *strSearch = [NSString stringWithFormat:#"%#",searchB.text];
if ([strSearch isEqualToString:#""])
{
[self showAllData];
return;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self CONTAINS[cd] %#",strSearch];
resultarray = [self.arrayALLData filteredArrayUsingPredicate:predicate];
[self.arrayPeopleList removeAllObjects];
[self.arrayPeopleList addObjectsFromArray:resultarray];
[_tblView reloadData];
return YES;
}
I am writing an iOS chat application wherein I have to show the users list with a search bar. I am getting the updated user list from the server after every 2 min.
The problem that I am facing is
Case:1
If I have the search bar active and I call reload table when the datasource is updated, now if I cancel the search, I do not get my original table. Only the filtered results are shown.
Case: 2
If I have the search bar active and I just update the data source and do not reload the table, now if I cancel the search, it loops to cellforrowatindexpath as many times as there are elements in the new datasource but it does not show the updated elements. Infact, it jumbles up the elements because it considers the new index paths but uses the old data.
By jumbled up I mean,
Say if the old datasource is a1, a2, a3 and a4 with avatar images a1, a2, a3, a4.
The new datasource is a5, a1, a2, a3, a4 with images a5, a1, a2, a3, a4.
So the jumbled view that I get is
a1 with a5 image,
a2 with a1 image,
a3 with a4 image
a4 with no image.
4 cells instead of 5.
Case: 3 (working correctly)
If I have the search bar active and I do not even update the data source, nothing happens when I cancel the search (as expected). I have to reload the table to get the updated view.
What I want is that it should update the table even if search is active and when I cancel the search I should get the updated table view. I know this can be achieved by reload table when cancel button is clicked but I am trying to find an elegant solution to this.
Also, please tell me the concept (the inner workings) behind why is this working like this.
My code:
- (void)refreshUserList
{
if(dtclass.updatedUserList && [resultsArray count] ==0)
{
userArray = dtclass.getUpdatedUserList;
[self.tableView reloadData];
[dtclass setUpdatedUserList:NO];
}
else if(dtclass.updatedUserList && [resultsArray count] !=0)
{
//Uncomment for Case:1
/*userArray = dtclass.getUpdatedUserList;
[dtclass setUpdatedUserList:NO];
[self.tableView reloadData];*/
//Uncomment for Case:2
/*userArray = dtclass.getUpdatedUserList;
[dtclass setUpdatedUserList:NO];*/
//remove else if code for Case:3
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
if (resultsArray.count != 0)
{
return [resultsArray count];
}
return userArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView setSeparatorInset:UIEdgeInsetsMake(0, 70, 0, 0)];
GlobalListTableViewCell *cell = (GlobalListTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"GlobalListCell"];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"GlobalListTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
//custome class User
User *currentUser;
if(resultsArray.count !=0)
{
currentUser = [resultsArray objectAtIndex:indexPath.row];
}
else
{
currentUser = [userArray objectAtIndex:indexPath.row];
}
cell.nameLabel.text = currentUser.getName;
cell.timeLabel.text = #"5 pm";
dispatch_async(fetchImage, ^{
if([[currentUser getAvatarUrl] length]!=0)
{
[self loadImagesWithURL:[NSString stringWithFormat:#"%#%#",#"http:",[currentUser getAvatarUrl]] IndexPath:indexPath];
}
});
cell.avatarImage.image = [UIImage imageNamed:#"defaultUser.png"];
cell.messageLabel.text = #"No message";
return cell;
}
-(void) loadImagesWithURL:(NSString *)imageURL IndexPath:(NSIndexPath *)indexPath
{
NSURL *url = [NSURL URLWithString:imageURL];
NSData *data = [[NSData alloc ] initWithContentsOfURL:url];
UIImage *img = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
GlobalListTableViewCell *cell = (GlobalListTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
cell.avatarImage.image = img;
});
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath
{
return 60;
}
- (void)filterContentForSearchText:(NSString*)searchText scope: (NSString*)scope
{
resultsArray = [[NSArray alloc] init];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF.getName contains[c] %#", searchText];
resultsArray = [userArray filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope: [[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex: [self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *) aSearchBar {
aSearchBar.text = nil;
}
Try this code for search ..
- (void)filterContentForSearchText:(NSString*)searchText
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.getName contains[c] %#",searchText];
_filteredGarages = [NSMutableArray arrayWithArray:[_allGarages filteredArrayUsingPredicate:predicate]];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[_filteredGarages removeAllObjects];
if([searchText length] != 0) {
[self filterContentForSearchText:searchText];
}
[self.tableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
isSearching = NO;
[self.tableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
if([searchBar.text isEqualToString:#""])
isSearching = NO;
else isSearching = YES;
[self.tableView reloadData];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
if([searchBar.text isEqualToString:#""])
isSearching = NO;
else isSearching = YES;
[self.tableView reloadData];
}
- (void)viewDidLoad {
[super viewDidLoad];
resultsArray = [[NSMutableArray alloc] init];
isSearching = NO;
userArray = [[NSMutableArray alloc] init];
userArray = [//GetYourData//];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [resultsArray count];
} else {
return [userArray count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Do you table view cell job here ...
if (tableView == self.searchDisplayController.searchResultsTableView) {
isSearching = YES;
//fill the cell using resultsArray
} else {
//fill the cell using userArray
}
}
I am using searchdisplaycontroller,I have a table view above that i have a search bar... the table view displays a list of object names.. for example if i have an json object like
json :{
name: testname;
age:12;
maths:50;
english:56;
science:45;
},
{
// list of similar json objects
}
i have displayed only name in table row using cell.name.text = [json valueforKey :#"name"];
when i dont search anything i can get the whole object when ever user presses the any row by writing
[json objectAtIndex:indexPath.row];
My problem is when i search the table i am not getting the correct object at index... for example i search something in the search bar the it displays rows with relevant objects. when i use the same [json objectAtIndex:indexPath.row]; wrong index objects gets assigned pls help here is my code
-(void)filtercontentForSearchText:(NSString *)searchtext scope:(NSString *)scope{
NSPredicate *resultpredicate=[NSPredicate predicateWithFormat:#"SELF contains [cd] %#",searchtext];
searchList=[[searchDataArray valueForKey:#"SubjectDescription" ] filteredArrayUsingPredicate:resultpredicate];
NSLog(#"searchlist %#",searchList );
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
[self filtercontentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles ] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
//This is didselectrowAtindex code...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"selected");
// if ([numberOfTouchesString isEqualToString:#"One"])
// {
NSArray *selected = [searchDataArray objectAtIndex:indexPath.row];
if (self.delegate && [self.delegate respondsToSelector:#selector(selectedSubject:)])
{
if (tableView == self.searchDisplayController.searchResultsTableView){
if ([self.searchDisplayController isActive]){
NSLog(#"searchlist %#",searchList);
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
id searchResult = [searchList objectAtIndex:indexPath.row];
int indexForResult = [json indexOfObject:searchResult];
NSLog(#"indexpath%d " , indexForResult);
searchAppDelObj.didselectjsondata=[json objectAtIndex:indexPath.row];//storing that json data in AppDelegate object
_serachStr = [searchList objectAtIndex:indexPath.row];
//searchAppDelObj.valuePass=(NSArray *)_serachStr;
NSLog(#" searchAppDelObj.valuePass %#",(NSArray *)_serachStr);
//[self.delegate selectedSubject:self];
}
}
else
{
LearningSearchCell *cell = (LearningSearchCell *)[self.learningSearchTableView cellForRowAtIndexPath:indexPath];
NSString *cellText = cell.subjectNameLabel.text;
searchAppDelObj.didselectstring=cellText;
searchAppDelObj.didSelectArray=[searchDataArray objectAtIndex:indexPath.row];
NSLog(#"appobjarray %#",searchAppDelObj.didSelectArray);
NSLog(#"AppObj.didselectstring %#",searchAppDelObj.didselectstring);
//searchAppDelObj.valuePass=selected;
//[self.delegate selectedSubject:self];
}
if (-[_comparestr isEqualToString:#"search"]) {
searchAppDelObj.valuePass=(NSArray *)_serachStr;
NSLog(#" searchAppDelObj.valuePass %#",(NSArray *)_serachStr);
[self.delegate selectedSubject:self];
}else{
NSLog(#"AppObj.didselectstring %#",searchAppDelObj.didselectstring);
searchAppDelObj.valuePass=selected;
[self.delegate selectedSubject:self];
}
[self.revealViewController revealToggleAnimated:YES];
}
}
//Here is CellForRowAtindexpath code.........
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"learningSearchCellIdentifier";
LearningSearchCell *cell = [self.learningSearchTableView dequeueReusableCellWithIdentifier:cellIdentifier ];
if ((tableView==self.learningSearchTableView)==YES)
{
cell.subjectNameLabel.text=[[json objectAtIndex:indexPath.row]valueForKey:#"name"];
//subjectString=cell.subjectLabel.text;
cell.teacherNameLabel.text=[[json objectAtIndex:indexPath.row]valueForKey:#"age"];
cell.subjecDataAndSessionLabel.text=[[json objectAtIndex:indexPath.row]valueForKey:#"maths"];
NSNumber *test =[[searchDataArray objectAtIndex:indexPath.row]valueForKey:#"Cohort"];
NSString *myString =[NSString stringWithFormat:#"%#",test];
cell.chorotLabel.text=myString;
}
else if (tableView==self.searchDisplayController.searchResultsTableView) {
cell.subjectNameLabel.text=[searchList objectAtIndex:indexPath.row];
NSLog(#"indexpath %d",indexPath.row);
cell.teacherNameLabel.text=[[json objectAtIndex:indexPath.row]valueForKey:#"age"];
cell.subjecDataAndSessionLabel.text=[[json objectAtIndex:indexPath.row]valueForKey:#"maths"];
NSNumber *test =[[searchDataArray objectAtIndex:indexPath.row]valueForKey:#"english"];
NSString *myString =[NSString stringWithFormat:#"%#",test];
cell.chorotLabel.text=myString;
}
else{
cell.subjectNameLabel.text=[json objectAtIndex:indexPath.row];
}
return cell;
}
hope this will help you
As I understood that you want only those name which set of characters contain in your search bar,
first use NSMutableArray *nameJson to add your all the name from json.
and Use NSArray *nameShowing
_nameShowing = _nameJson;
and reload the tableview
uptill now you have your all your name in your table view , and now you search particular name
2. - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
self.nameShowing = nil;
self.nameShowing = [[NSArray alloc]init];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"SELF contains %#", self.searchbar.text];
self.nameShowing = [self.nameJson filteredArrayUsingPredicate:filter];
if(([self.searchbar.text isEqual:#""]))
{
self.nameShowing = self.nameJson;
}
[self.tblView reloadData];
}
I have text field from which, I want that if user enters any data and it matches to the any of the cell in tableView then it must show.I have used text field for searching the data from table.
This is how, I am populating data in the tableView as below:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSLog(#"Number of Sections");
if(section == 0)
return #"Sales";
if(section == 1)
return #"Soft Skills";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section==0)
{
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
int count=[resultArray count];
NSLog(#"resultArry Row Counts is %d",count);
return [resultArray count];
}
else{
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
int count=[resultArrayOne count];
NSLog(#"resultArry Row Counts is %d",count);
return [resultArrayOne count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Table Cell Data");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if (indexPath.section==0) {
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
ObjectData *theCellData = [resultArray objectAtIndex:indexPath.row];
NSString *cellValue =theCellData.sub_Category;
NSLog(#"Cell Values %#",cellValue);
cell.textLabel.text = cellValue;
return cell;
}
else {
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
ObjectData *theCellData = [resultArrayOne objectAtIndex:indexPath.row];
NSString *cellValue =theCellData.sub_Category;
NSLog(#"Cell Values %#",cellValue);
cell.textLabel.text = cellValue;
return cell;
}
}
-(void)textFieldTextDidChange:(UITextField*)tf{
NSString*test = searchTextField.text ;
}
try like this may be it helps you,
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", txtSearch.text];
NSArray *ResultArray = [yourArray filteredArrayUsingPredicate:predicate];
[table reloadData];
return YES;
}
in above code replace Your array.
if you want to show the table data which is having substring of the textfield then use below code.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#", txtSearch.text];
Search Data from UITableview ,You can Use SearchBar. you can see in many Denmo projects or example all can use SearchBar in Searching Data in Tableview . the below code of SearchBar.
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
searchName = [[NSMutableArray alloc]init] ;
for(NSString *name in yourArraySeaching)
{
NSRange r = [name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound)
{
[searchName addObject:name];
tempSearch=1;
}
}
}
First of all, you need one more temp array for searching purpose same as main array, one array maintaining searching array's IDs.
Boolean value for Searching :: bool searching;
Code ::
-(void)textFieldTextDidChange:(UITextField*)tf {
int len = [[tf.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length];
if (len < [mainArray count]) {
[tempArray removeAllObjects];
[tempArrayIds removeAllObjects];
for(NSString *curString in tempArray)
{
NSString *substringRange = [curString substringWithRange:NSMakeRange(0, tf.length)];
// Converting SearchChar and Firstchar of contestname into lower case
NSString *searchChar = [tf lowercaseString];
NSString *FirstChar = [substringRange lowercaseString];
//NSLog(#"values is %#",substringRange);
if ([FirstChar isEqualToString:searchChar]) {
if ([tf isEqualToString:#""]) {
searching = false;
[tf resignFirstResponder];
}
else
{
searching = true;
[tempArray addObject:curString];
indexVal = [tempArray indexOfObject:curString];
NSString *s = [NSString stringWithFormat:#"%d", indexVal];
[tempArrayIds addObject:s];
}
}
}
[tblView reloadData];
}
Table Methods ::
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (searching)
return [tempArray count];
else
return [mainArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(searching)
{
int k = [[tempArrayIds objectAtIndex:indexPath.row] intValue];
cell.title.text = [mainArray objectAtIndex:k];
}
else
{
cell.title.text = [mainArray objectAtIndex:indexPath.row];
}
return cell;
}
Hopefully, it'll help you.
Thanks.
I usually prefer using the freely available Sensible TableView framework to do that. The framework will fetch the data and provide all the searching functionality for you automatically.
I have a TableView with many rows, most are not visible at the time of loading viewController. The rows of UITableView are extracted from a SQLite database. How can I make do that the SearchBar search between all rows and not just the visible ones?
In header file:
#interface ExhibitorsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>{
BOOL isSearchOn;
BOOL canSelectRow;
NSMutableArray * listOfExpositors;
NSMutableArray * searchResult;
}
//....
#end
In implementation file
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
if(isSearchOn){
return [searchResult count];
//In this array there are the elements after use of searchBar
}else{
int number=[self.mutableArray count];
//In this array there are all elements of database, extracts in viewDidLoad()
return number;
}
}
- (UITableViewCell *)tableView:(UITableView *)aTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] ;
}
if(isSearchOn){
NSString * cellValue = [searchResult objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
}else{
//loading data from the database
Database *currow =[self.mutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = currow.name;
[listOfExpositors addObject:cell.textLabel.text];
//here only loads the list of names visible and not the entire table
//How do I put all the elements in this array?
NSLog(#" %#", listOfExpositors);
isSearchOn = NO;
canSelectRow = YES;
}
}
-(void) doneSearching{
isSearchOn = NO;
canSelectRow = YES;
self.tableView.scrollEnabled = YES;
[self.searchBar resignFirstResponder];
[self.tableView reloadData];
}
-(void) searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
isSearchOn = YES;
if(self.searchBar.text.length>0){
canSelectRow=YES;
self.tableView.scrollEnabled = YES;
}else{
canSelectRow= NO;
self.tableView.scrollEnabled = NO;
}
}
-(void) searchExpositorsTableView{
[searchResult removeAllObjects];
for (NSString *str in listOfExpositors){
NSRange titleResultsRange = [str rangeOfString:self.searchBar.text options:
NSCaseInsensitiveSearch];;
if (titleResultsRange.length >0) {
[searchResult addObject:str];
}
}
NSLog(#"%#", searchResult);
}
-(void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
if([searchText length]>0){
canSelectRow = YES;
self.tableView.scrollEnabled = YES;
[self searchExpositorsTableView];
}else{
canSelectRow = NO;
self.tableView.scrollEnabled = NO;
}
[self.tableView reloadData];
}
-(void) searchBarSearchButtonClicked:(UISearchBar *)searchBar{
[self searchExpositorsTableView];
[self.searchBar resignFirstResponder];
}
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(canSelectRow){
return indexPath;
}else{
return nil;
}
NSLog(#"%d", indexPath.row);
}
It was wrong to use the array created in cellForRowAtIndexPath because it was limited only to the visible elements. I then used the NSMutableArray created in viewDidLoad () that does contain all the elements of the database. I changed the following methods:
- (UITableViewCell *)tableView:(UITableView *)aTableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//....
if(isSearchOn){
NSString * cellValue = [searchResult objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
}else{
Database *currow =[self.mutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = currow.name;
//Should be removed this array and used to another, self.mutableArray
//[listOfExpositors addObject:cell.textLabel.text];
// NSLog(#" %#", listOfExpositors);
isSearchOn = NO;
canSelectRow = YES;
}
}
Method for research
-(void) searchExpositorsTableView{
[searchResult removeAllObjects];
for (Database *currow in self.mutableArray){
/*In self.mutableArray there are all elements because is created in
viewDidLoad*/
NSLog(#"list of expositors %#", self.mutableArray);
NSRange titleResultsRange = [currow.name rangeOfString:self.searchBar.text options: NSCaseInsensitiveSearch];
if (titleResultsRange.length >0) {
[searchResult addObject:currow.name];
}
}
NSLog(#"%#", searchResult);
}