I have a SearchBar on my tableView. It is correctly working when typing to search through the table view. However, when the cancel button is pressed, the tableView is not reloading the data.
-(void)viewDidLoad {
[super viewDidLoad];
isFiltered = false;
self.searchController = [[UISearchController alloc]
initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.tableView.tableHeaderView = self.searchController.searchBar;
self.definesPresentationContext = YES;
[self.searchController.searchBar sizeToFit];
}
- (void)viewWillAppear:(BOOL)animated {
NSBundle *bundle = [NSBundle mainBundle];
self.files = [bundle pathsForResourcesOfType:#"pdf" inDirectory:#"thepdfpowerpoints"];
NSString *documentsDirectoryPath = [self.files objectAtIndex:thepath.row];
self.title = #"Devo Songs";
self.filenames = [[documentsDirectoryPath lastPathComponent] stringByDeletingPathExtension];
NSMutableArray *names = [NSMutableArray arrayWithCapacity:[self.files count]];
for (NSString *path in self.files) {
[names addObject:[[path lastPathComponent] stringByDeletingPathExtension]];
}
//self.files = names;
self.files = [names sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSLog(#"FILESLOAD%#", self.files);
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
-(void) updateSearchResultsForSearchController:(UISearchController *)searchController {
isFiltered = true;
NSString *searchText = self.searchController.searchBar.text;
searchResults = [[NSMutableArray alloc] init];
for (NSString *file in self.files) {
NSRange nameRange = [file rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound) {
[searchResults addObject:file];
}
}
[self.tableView reloadData];
}
-(void) searchBarCancelButtonClicked:(UISearchBar *)searchBar {
//self.tableView.tableHeaderView = searchBar;
NSLog(#"Cancel");
isFiltered=false;
[self.tableView reloadData];
}
I have added an NSLog in cellForRowAtIndexPath This is showing in console when I first go to the view, but it is not being called when I click the cancel button.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Loading");
The code for number of rows/section is:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
if (isFiltered) {
return [searchResults count];
}
else {
return [self.files count];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 1;
}
Tapping the search bar's "Cancel" button clears the search text...
and then calls updateSearchResultsForSearchController.
So your current code is setting isFiltered to true again, and then reloading the table view based on an empty searchResults array.
You don't really need to implement searchBarCancelButtonClicked unless you want to do something other than refresh your table view.
Try changing your updateSearchResultsForSearchController method to this - it will use the full files array if no text has been entered in the search field. Otherwise, it will filter the files array.
-(void) updateSearchResultsForSearchController:(UISearchController *)searchController {
NSLog(#"update"); // just to show when this is being called
NSString *searchText = self.searchController.searchBar.text;
if (searchText.length != 0) {
isFiltered = YES;
searchResults = [[NSMutableArray alloc] init];
for (NSString *file in self.files) {
NSRange nameRange = [file rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound) {
[searchResults addObject:file];
}
}
} else {
isFiltered = NO;
}
[self.tableView reloadData];
}
Related
I have one tableview and I created one UISearchController programmatically and added to tableview.
Initially it looks good but when I press on inside the search bar it looks below.
I don't want to keep my searchbar in navigation bar. And I can not use UITableViewController.
Find the code below which I implemented.
My .h file
#property (strong, nonatomic) UISearchController *searchController;
NSMutableArray *tableData;
NSArray *filteredContentList;
My .m file
// New SearchController.
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.searchController.searchBar.searchBarStyle = UISearchBarStyleProminent;
[self.searchController.searchBar sizeToFit];
self.tblUserList.tableHeaderView = self.searchController.searchBar;
self.definesPresentationContext = YES;
#pragma mark - UISearchDisplayDelegate
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
NSString *searchString = searchController.searchBar.text;
NSPredicate *resultPredicate;
//resultPredicate = [NSPredicate predicateWithFormat:#"displayname contains[c] %#",searchString];
resultPredicate = [NSPredicate predicateWithFormat:#"value contains[c] %#", searchString];
filteredContentList = [tableData filteredArrayUsingPredicate:resultPredicate];
//filteredContentList = [[tableData valueForKey:#"data"] filteredArrayUsingPredicate:resultPredicate];
[self.tblUserList reloadData];
}
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope {
[self updateSearchResultsForSearchController:self.searchController];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
CGRect searchBarFrame = self.searchController.searchBar.frame;
[self.tblUserList scrollRectToVisible:searchBarFrame animated:NO];
return NSNotFound;
}
I want to show my searchbar above the tableview not in naviationbar.
Thanks in advance.
Late answer by myself.
I use UITextFiled instead of UISearchBar. Below is my code implementation.
[self.searchTextField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
And my textFieldDidChange method
-(void)textFieldDidChange:(UITextField *)textField
{
searchTextString=textField.text;
[self updateSearchArray:searchTextString];
}
-(void)updateSearchArray:(NSString *)searchText {
if(searchText.length==0) {
isFilter=NO;
} else {
isFilter=YES;
filteredContentList = [[NSMutableArray alloc]init];
NSPredicate *resultPredicate;
resultPredicate = [NSPredicate predicateWithFormat:#"value contains[c] %#", searchText];
filteredContentList = [tableData filteredArrayUsingPredicate:resultPredicate];
[self.tblUserList reloadData];
}
}
And my TableView methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSInteger numOfSections = 0;
if ([filteredContentList count] || [tableData count]) {
_tblUserList.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
numOfSections = 1;
_tblUserList.backgroundView = nil;
} else {
UILabel *noDataLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, _tblUserList.bounds.size.width, _tblUserList.bounds.size.height)];
noDataLabel.text = NSLocalizedString(#"No Users found", #"Message");
noDataLabel.textColor = [UIColor blackColor];
noDataLabel.textAlignment = NSTextAlignmentCenter;
_tblUserList.backgroundView = noDataLabel;
_tblUserList.separatorStyle = UITableViewCellSeparatorStyleNone;
}
return numOfSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
/*if (isSearching) {
return [filteredContentList count];
}
else {
return [tableData count];
}*/
if (isFilter) {
return [filteredContentList count];
} else {
return [tableData count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
//cell.textLabel.text = [[tableData objectAtIndex:indexPath.row] valueForKeyPath:#"data.displayname"];
// Configure the cell...
if (isFilter) {
//cell.textLabel.text = [filteredContentList objectAtIndex:indexPath.row];
cell.textLabel.text = [[filteredContentList objectAtIndex:indexPath.row] valueForKeyPath:#"data.displayname"];
}
else {
cell.textLabel.text = [[tableData objectAtIndex:indexPath.row] valueForKeyPath:#"data.displayname"];
}
return cell;
}
I'm stumped. For some reason, when I tap my tableView cell, didSelectRowAtIndexPath is not executing? And yes, my tableView delegate is set, and data is populated in the cell label. Am I missing something obvious from my below? Essentially, when my user taps the tableView cell, the contents of the cell label should appear in a textfield.
.h
#interface RegisterViewController : UIViewController <UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate> {
}
#property (nonatomic) IBOutlet UITableView *tableView;
#end
.m
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.hidden = NO;
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
- (void)LoadJson_search{
searchArray=[[NSMutableArray alloc]init];
// NSLog(#"str......%#",strSearch);
// This API key is from https://developers.google.com/maps/web/
NSString *str1 = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/queryautocomplete/json?input=%#&key=AIzaSyAm7buitimhMgE1dKV2j4_7doULluiiDzU", strSearch];
NSURL *url = [NSURL URLWithString:str1];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error=nil;
if(data.length==0)
{
}
else
{
NSDictionary *jsondic= [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
// NSLog(#"1,,,,%#",jsondic);
[searchArray removeAllObjects];
if([[jsondic objectForKey:#"status"]isEqualToString:#"ZERO_RESULTS"])
{
}
else if([[jsondic objectForKey:#"status"]isEqualToString:#"INVALID_REQUEST"])
{
}
else
{
for(int i=0;i<[jsondic.allKeys count];i++)
{
NSString *str1=[[[jsondic objectForKey:#"predictions"] objectAtIndex:i] objectForKey:#"description"];
[searchArray addObject:str1];
}
self.tableView.hidden = NO;
// NSLog(#"%#", searchArray);
}
if (searchArray.count == 0) {
self.tableView.hidden = YES;
}else{
[self.tableView reloadData];
}
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// if (self.addressField.tag == 3) {
if (textField == self.addressField) {
strSearch = [self.addressField.text stringByReplacingCharactersInRange:range withString:string];
if([string isEqualToString:#" "]){
}else{
[self LoadJson_search];
}}
// }
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField{
self.tableView.hidden = YES;
[self.tableView reloadData];
return YES;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return searchArray.count;
}
-(UITableViewCell *)tableView:(UITableView*)aTableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"cell"];
if(!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = [searchArray objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"TAPPED CELL");
self.addressField.text = [searchArray objectAtIndex:indexPath.row];
self.tableView.hidden = YES;
[self.tableView reloadData];
}
Try with the next line in your viewDidLoad:
self.tableView.allowsSelection = YES;
Or check that property in your storyboard. Well you can try with the cell too like this:
// This line do not affect the selection delegate only the style
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.userInteractionEnabled = YES;
I have added my delegate method and
I have a UITableView with a list of names. It has sections with an alphabetical index on the right hand side (see picture).
My program crashes whenever I enter a first character in the search field. I get the following error:
UpdateSearchResultsForSearchController
[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
Understand I am trying to access an empty array, in the method UpdateSearchResultsForSearchController.
The program crashes in the last line of the method.
[((UITableViewController *)self.searchController.searchResultsController).tableView reloadData];
Here is the header
#import <UIKit/UIKit.h>
#import "EmployeeDatabase.h"
#interface EmployeeListViewController : UITableViewController<UISearchResultsUpdating, UISearchBarDelegate>
#property (nonatomic, strong) NSMutableArray *employees;
#property (nonatomic, strong) UISearchController *searchController;
#property (nonatomic, strong) NSMutableArray *tableSections;
#property (nonatomic, strong) NSMutableArray *tableSectionsAndItems;
#end
and here is the implementation
#import "EmployeeListViewController.h"
#import "EmployeeDetailViewController.h"
#implementation EmployeeListViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeTableContent];
[self initializeSearchController];
[self styleTableView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Initialization methods
- (void)initializeTableContent {
self.employees = [EmployeeDatabase getEmployees];
self.tableSections = [NSMutableArray array];
self.tableSectionsAndItems = [NSMutableArray array];
for (employee *name in self.employees) {
NSString *key = [[name.lstNme substringToIndex: 1] uppercaseString];
if ([self.tableSections containsObject:key] == false) {
[self.tableSections addObject:key];
NSMutableArray *tmpArray = [NSMutableArray array];
[tmpArray addObject:name.fulNme];
NSMutableDictionary *tmpDictionary = [NSMutableDictionary dictionaryWithObject:tmpArray forKey:key];
[self.tableSectionsAndItems addObject:tmpDictionary];
} else {
NSMutableArray *tmpArray = [NSMutableArray array];
NSUInteger index = [self.tableSections indexOfObject:key];
NSMutableDictionary *tmpDictionary = [self.tableSectionsAndItems objectAtIndex:index];
tmpArray = [tmpDictionary objectForKey:key];
[tmpArray addObject:name.fulNme];
[self.tableSectionsAndItems removeObjectAtIndex:index];
[self.tableSectionsAndItems addObject:tmpDictionary];
}
}
}
- (void)initializeSearchController {
//instantiate a search results controller for presenting the search/filter results (will be presented on top of the parent table view)
UITableViewController *searchResultsController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
searchResultsController.tableView.dataSource = self;
searchResultsController.tableView.delegate = self;
//instantiate a UISearchController - passing in the search results controller table
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
//this view controller can be covered by theUISearchController's view (i.e. search/filter table)
self.definesPresentationContext = YES;
//define the frame for the UISearchController's search bar and tint
self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x,
self.searchController.searchBar.frame.origin.y,
self.searchController.searchBar.frame.size.width, 44.0);
self.searchController.searchBar.tintColor = [UIColor whiteColor];
//add the UISearchController's search bar to the header of this table
self.tableView.tableHeaderView = self.searchController.searchBar;
//this ViewController will be responsible for implementing UISearchResultsDialog protocol method(s) - so handling what happens when user types into the search bar
self.searchController.searchResultsUpdater = self;
//this ViewController will be responsisble for implementing UISearchBarDelegate protocol methods(s)
self.searchController.searchBar.delegate = self;
}
- (void)styleTableView {
[[self tableView] setSectionIndexColor:[UIColor colorWithRed:100.0f/255.0f green:100.0f/255.0f blue:100.0f/255.0f alpha:1.0f]];
[[self tableView] setSectionIndexBackgroundColor:[UIColor colorWithRed:230.0f/255.0f green:230.0f/255.0f blue:230.0f/255.0f alpha:1.0f]];
}
#pragma mark - UITableViewDataSource methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.tableSections count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSDictionary *sectionItems = [self.tableSectionsAndItems objectAtIndex:section];
NSArray *namesForSection = [sectionItems objectForKey:[self.tableSections objectAtIndex:section]];
return [namesForSection count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [self.tableSections objectAtIndex:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellReuseId = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellReuseId];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellReuseId];
}
NSDictionary *sectionItems = [self.tableSectionsAndItems objectAtIndex:indexPath.section];
NSArray *namesForSection = [sectionItems objectForKey:[self.tableSections objectAtIndex:indexPath.section]];
cell.textLabel.text = [namesForSection objectAtIndex:indexPath.row];
//show accessory disclosure indicators on cells only when user has typed into the search box
if(self.searchController.searchBar.text.length > 0) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
#pragma mark - UITableViewDelegate methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *sectionItems = [self.tableSectionsAndItems objectAtIndex:indexPath.section];
NSArray *namesForSection = [sectionItems objectForKey:[self.tableSections objectAtIndex:indexPath.section]];
NSString *selectedItem = [namesForSection objectAtIndex:indexPath.row];
//Log
NSLog(#"User selected %#", selectedItem);
}
//#pragma Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
employee *employee = self.employees[indexPath.row];
EmployeeDetailViewController *employeeDetailViewController = segue.destinationViewController;
employeeDetailViewController.detailItem = employee;
}
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
//only show section index titles if there is no text in the search bar
if(!(self.searchController.searchBar.text.length > 0)) {
NSArray *indexTitles = self.tableSections;
//HERE
//*indexTitles = [Item fetchDistinctItemGroupsInManagedObjectContext:self.managedObjectContext];
return indexTitles;
} else {
return nil;
}
}
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
view.tintColor = [UIColor colorWithRed:100.0f/255.0f green:100.0f/255.0f blue:100.0f/255.0f alpha:1.0f];
UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
[header.textLabel setTextColor:[UIColor whiteColor]];
}
#pragma mark - UISearchResultsUpdating
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
//get search text from user input
NSString *searchText = [self.searchController.searchBar text];
//exit if there is no search text (i.e. user tapped on the search bar and did not enter text yet)
if(!([searchText length] > 0)) {
return;
}
//handle when there is search text entered by the user
else {
//based on the user's search, we will update the contents of the tableSections and tableSectionsAndItems properties
[self.tableSections removeAllObjects];
[self.tableSectionsAndItems removeAllObjects];
NSString *firstSearchCharacter = [searchText substringToIndex:1];
//handle when user taps into search bear and there is no text entered yet
if([searchText length] == 0) {
//self.tableSections = [[Item fetchDistinctItemGroupsInManagedObjectContext:self.managedObjectContext] mutableCopy];
//self.tableSectionsAndItems = [[Item fetchItemNamesByGroupInManagedObjectContext:self.managedObjectContext] mutableCopy];
}
//handle when user types in one or more characters in the search bar
else if(searchText.length > 0) {
//the table section will always be based off of the first letter of the group
NSString *upperCaseFirstSearchCharacter = [firstSearchCharacter uppercaseString];
self.tableSections = [[[NSArray alloc] initWithObjects:upperCaseFirstSearchCharacter, nil] mutableCopy];
//there will only be one section (based on the first letter of the search text) - but the property requires an array for cases when there are multiple sections
//NSDictionary *namesByGroup = [Item fetchItemNamesByGroupFilteredBySearchText:searchText ////inManagedObjectContext:self.managedObjectContext];
//self.tableSectionsAndItems = [[[NSArray alloc] initWithObjects:namesByGroup, nil] mutableCopy];
}
//now that the tableSections and tableSectionsAndItems properties are updated, reload the UISearchController's tableview
[((UITableViewController *)self.searchController.searchResultsController).tableView reloadData];
}
}
#pragma mark - UISearchBarDelegate methods
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self.tableSections removeAllObjects];
[self.tableSectionsAndItems removeAllObjects];
//self.tableSections = [[Item fetchDistinctItemGroupsInManagedObjectContext:self.managedObjectContext] mutableCopy];
//self.tableSectionsAndItems = [[Item fetchItemNamesByGroupInManagedObjectContext:self.managedObjectContext] mutableCopy];
}
#end
The problem is that, your are removing all objects at this line
[self.tableSectionsAndItems removeAllObjects];
and you have commented the lines, which again feels that array, just above the lines which you mentioned in your question. so, uncomment the following lines
//NSDictionary *namesByGroup = [Item fetchItemNamesByGroupFilteredBySearchText:searchText ////inManagedObjectContext:self.managedObjectContext];
//self.tableSectionsAndItems = [[[NSArray alloc] initWithObjects:namesByGroup, nil] mutableCopy];
And in numberOfRows Method, you are accessing the object at index on empty array that leads to crash.
[self.tableSectionsAndItems objectAtIndex:section];
So, uncomment those two lines above, in the following method and it will fix.
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController
Try and share your results.
I have a UITableView with search bar function. However, when i search for any keyword (Please refer to screenshot as attached), search result will be repeated and return more than 1 result.
My expected result should be search result will reflect accordingly based on keyword entered.
Your help is much appreciated. Please help, thank you.
#interface Friend_ViewController ()
#end
#implementation Friend_ViewController{
NSMutableArray *tableData;
UITableView *tableView;
BOOL isFiltered;
NSMutableArray *stateNamesArray;
NSArray *searchResult;
}
- (void)viewDidLoad {
[super viewDidLoad];
isFiltered =false;
UIImage* image3 = [UIImage imageNamed:#"Add_Friend"];
CGRect frameimg = CGRectMake(0,0, image3.size.width -10, image3.size.height);
UIButton *btn_add_friends = [[UIButton alloc] initWithFrame:frameimg];
[btn_add_friends setBackgroundImage:image3 forState:UIControlStateNormal];
[btn_add_friends addTarget:self action:#selector(addFriendButtonDidPressed:)
forControlEvents:UIControlEventTouchUpInside];
[btn_add_friends setShowsTouchWhenHighlighted:YES];
UIBarButtonItem *btn_add_friends_item =[[UIBarButtonItem alloc] initWithCustomView:btn_add_friends];
self.navigationItem.rightBarButtonItem =btn_add_friends_item;
stateNamesArray = #[#"Alabama", #"Alaska", #"Arizona", #"Arkansas", #"California", #"Colorado", #"Connecticut", #"Delaware", #"Florida", #"Georgia", #"Hawaii", #"Idaho", #"Illinois", #"Indiana", #"Iowa", #"Kansas", #"Kentucky", #"Louisiana", #"Maine", #"Maryland", #"Massachusetts", #"Michigan",
#"Minnesota", #"Mississippi", #"Missouri", #"Montana", #"Nebraska", #"Nevada", #"New Hampshire",
#"New Jersey", #"New Mexico", #"New York", #"North Carolina", #"North Dakota", #"Ohio",
#"Oklahoma", #"Oregon", #"Pennsylvania", #"Rhode Island", #"South Carolina", #"South Dakota",
#"Tennessee", #"Texas", #"Utah", #"Vermont", #"Virginia", #"Washington", #"West Virginia",
#"Wisconsin", #"Wyoming"];
NSInteger indexLabelLettersCount = [[UILocalizedIndexedCollation currentCollation] sectionTitles].count;
NSMutableArray *allSections = [[NSMutableArray alloc] initWithCapacity:indexLabelLettersCount];
for (int i = 0; i < indexLabelLettersCount; i++) {
[allSections addObject:[NSMutableArray array]];
}
for(NSString *theState in stateNamesArray){
NSInteger sectionNumber = [[UILocalizedIndexedCollation currentCollation] sectionForObject:theState collationStringSelector:#selector(lowercaseString)];
[allSections[sectionNumber] addObject:theState];
}
NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
self.activeSectionIndices = [NSMutableDictionary dictionary];
self.activeSectionTitles = [NSMutableArray array];
for (int i = 0; i < indexLabelLettersCount; i++) {
NSArray *statesForSection = allSections[i];
NSString *indexTitleForSection = [[UILocalizedIndexedCollation currentCollation] sectionTitles][i];
if (statesForSection.count > 0) {
[self.activeSectionTitles addObject:indexTitleForSection];
NSArray *tmpSectionStates = allSections[i];
tmpSectionStates = [tmpSectionStates sortedArrayUsingSelector:#selector(compare:)];
[sortedArray addObject:tmpSectionStates];
}
NSNumber *index = [NSNumber numberWithInt:MAX(self.activeSectionTitles.count - 1, 0)];
self.activeSectionIndices[indexTitleForSection] = index;
}
tableData = sortedArray;
self.tableView.sectionHeaderHeight = 25;
self.navigationController.navigationBar.translucent = NO;
tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.navigationController.navigationBar.translucent = NO;
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.tableView.tableHeaderView = self.searchController.searchBar;
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.definesPresentationContext = YES;
[self.searchController.searchBar sizeToFit];
[self.view addSubview:self.searchBar];
searchResult = [NSMutableArray arrayWithCapacity:[stateNamesArray count]];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(nonnull NSString *)searchText
{
if(searchText.length == 0)
{
isFiltered = NO;
}
else
{
isFiltered = YES;
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF CONTAINS %#",
searchText];
searchResult = [stateNamesArray filteredArrayUsingPredicate:resultPredicate];
}
[self.tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView: (UITableView *) tableView{
return tableData.count;
}
- (NSInteger)tableView: (UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(isFiltered){
return searchResult.count;
}
else
{
NSArray *arr = tableData[section];
return arr.count;
}
}
- (UITableViewCell *) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
if(isFiltered){
cell.textLabel.text = [searchResult objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:#"Home"];
}
else{
NSArray *arr = tableData[indexPath.section];//get the current section array
cell.textLabel.text = arr[indexPath.row];//get the row for the current section
cell.imageView.image = [UIImage imageNamed:#"Home"];
}
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
if(isFiltered)
{
return nil;
}
return self.activeSectionTitles[section];
}
#end
</pre></code>
You are always returning tableData.count in numberOfSectionsInTableView so every row is repeated tableData.count times.
- (NSInteger)numberOfSectionsInTableView: (UITableView *) tableView{
return isFiltered ? 1 : tableData.count;
}
- (NSInteger)tableView: (UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray sectionArray = (NSArray *)tableData[section];
return isFiltered ? 1 : sectionArray.count;
}
You are always returning tableData.count in numberOfSectionsInTableView so
You need to return proper section count.
- (NSInteger)numberOfSectionsInTableView: (UITableView *) tableView{
return isFiltered ? 1 : tableData.count;
}
I hope this will help you. :)
update this code
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(nonnull NSString *)searchText
{
//Add below line of code
[searchText removeAllObjects];
if(searchText.length == 0)
{
isFiltered = NO;
}
else
{
isFiltered = YES;
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF CONTAINS %#",
searchText];
searchResult = [stateNamesArray filteredArrayUsingPredicate:resultPredicate];
}
[self.tableView reloadData];
}
This method calls on every character, so it search and result store in array. You are not removing object from array so it keep adding object in it. That's why you are getting this result.
[searchText removeAllObjects];
This line of code remove all objects from array.
I am working on UITableView where I have a list of contacts. All the contacts are coming form a webservice in JSON format. I already parse it in my tableView, now I want to add a search logic to search contacts.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ChatListCell *cell=[tableView dequeueReusableCellWithIdentifier:#"contactListCell"];
if(!cell){
cell = [[ChatListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"contactListCell"];
}
ChatListData *chatlistData = [chatList objectAtIndex:indexPath.row];
NSString *txtName = chatlistData.name;
NSLog(#"name %#", txtName);
NSData *emojiData = [txtName dataUsingEncoding:NSUTF8StringEncoding];
NSString *emojiTxtName = [[NSString alloc] initWithData:emojiData encoding:NSNonLossyASCIIStringEncoding];
cell.txtName.text = emojiTxtName;
cell.txtTime.text = chatlistData.time;
NSString *stringImg = #"image";
NSString *stringVideo = #"video";
if(![chatlistData.mime_type isEqual: [NSNull null]]){
if ([chatlistData.mime_type rangeOfString:stringImg].location == NSNotFound || [chatlistData.mime_type rangeOfString:stringVideo].location == NSNotFound) {
if ([chatlistData.mime_type rangeOfString:stringImg].location == NSNotFound) {
cell.txtMsg.text = #"Image";
}else if([chatlistData.mime_type rangeOfString:stringVideo].location == NSNotFound){
cell.txtMsg.text = #"Video";
}
}else {
NSString *txtMsg = chatlistData.body;
NSData *emojiData = [txtMsg dataUsingEncoding:NSUTF8StringEncoding];
NSString *emojiTxtMsg = [[NSString alloc] initWithData:emojiData encoding:NSNonLossyASCIIStringEncoding];
cell.txtMsg.text = emojiTxtMsg;
}
}else {
NSString *txtMsg = chatlistData.body;
NSData *emojiData = [txtMsg dataUsingEncoding:NSUTF8StringEncoding];
NSString *emojiTxtMsg = [[NSString alloc] initWithData:emojiData encoding:NSNonLossyASCIIStringEncoding];
cell.txtMsg.text = emojiTxtMsg;
}
return cell;
}
- (void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//http://app.wazapper.com/api/users/inbox/45/#api_917838828123
ChatListData *chatlistData = [chatList objectAtIndex:indexPath.row];
if(![chatlistData.contact isEqual: [NSNull null]]){
NSString *chatUrl = [NSString stringWithFormat:#"http://app.wazapper.com/api/users/inbox/%#/#api_%#", [[User sharedInstance] userId], chatlistData.contact];
chatViewController.chatUrl = chatUrl;
[[NSNotificationCenter defaultCenter] postNotificationName:#"ChangeChatList" object:chatUrl];
}
}
this is my little piece of code, please give me some idea about it, I have already added the search bar in UITableView, I just need a logic for this purpose.
First add UISearchBarDelegate to your ViewController, then add this method to filter your search.
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
NSPredicate *pre0 = [NSPredicate predicateWithFormat:#"Fname contains[cd] %#", searchText];
NSPredicate *pre1 = [NSPredicate predicateWithFormat:#"Lname contains[cd] %#", searchText];
NSPredicate *preAll = [NSCompoundPredicate orPredicateWithSubpredicates:#[pre0, pre1]];
NSArray *filterAry= [jsonAry filteredArrayUsingPredicate:preAll];
}
UI implementation:
- (void)setupSearchBar {
CGFloat ySearchBarPosition = self.navigationController.navigationBar.bounds.size.height;
CGRect viewBounds = self.view.bounds;
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(CGRectGetMinX(viewBounds), ySearchBarPosition, CGRectGetWidth(viewBounds), kHeightDefault44)];
self.searchBar.backgroundImage = [[UIImage alloc] init];
self.searchBar.barTintColor = kYourBarTintColor;
self.searchBar.tintColor = kYourTintColor;
self.searchBar.delegate = self;
self.searchBar.placeholder = NSLocalizedString(#"searchBar.placeholder", nil);
self.searchBar.showsCancelButton = YES;
for (UIView *subview in self.searchBar.subviews) {
for (UIView *subSubview in subview.subviews) {
if ([subSubview conformsToProtocol:#protocol(UITextInputTraits)]) {
UITextField *textField = (UITextField *)subSubview;
textField.returnKeyType = UIReturnKeyDone;
textField.backgroundColor = kColorUnregisteredDevicesSearchBarBackground;
textField.textColor = kColorUnregisteredDevicesSearchBarText;
}
if ([subSubview isKindOfClass:NSClassFromString(#"UINavigationButton")]) {
UIButton *cancelBarButton = (UIButton *)subSubview;
cancelBarButton.tintColor = kColorUnregisteredDevicesSearchBarCancelButtonTintColor;
}
}
}
self.tableView.tableHeaderView = self.searchBar;
self.tableView.contentOffset = CGPointMake(0.0, self.tableView.tableHeaderView.bounds.size.height);
}
call this method where you create your tableView, before this line of code:
[self.view addSubview:self.yourTableView];
Functionality implementation:
1. You have to add UISearchBarDelegate on your .h class.
2. Use this delegation methods:
// delegation methods
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[self reloadModelAndTable];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
self.searchBar.text = #"";
[self.tableView reloadData];
[self.searchBar resignFirstResponder];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self.searchBar resignFirstResponder];
}
// private methods
- (void)reloadModelAndTable:(NSTimer *)timer {
[self filterModelForSearch:self.searchBar.text];
[self.tableView reloadData];
}
- (void)filterModelForSearch:(NSString *)searchText {
NSMutableArray *records = (NSMutableArray *)[self.unregisteredDevicesList mutableCopy];
NSIndexSet *resultSet = [records indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
YourModel *model = (YourModel *)obj;
BOOL hasObjects = [self resultHasObjects:model withSearchText:searchText];
return hasObjects;
}];
self.yourArrayWhichPopulatesTheTable = [[records objectsAtIndexes:resultSet] mutableCopy];
}
- (BOOL)resultHasObjects:(YourModel *)model withSearchText:(NSString *)searchText{
// I consider you make search for name
return ((model.name.length > 0) && [self containsString:model.name searchText:searchText]);
}
- (BOOL)containsString:(NSString *)haystack searchText:(NSString *)needle {
if (haystack) {
NSRange range = [haystack rangeOfString:needle options:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch];
return range.location != NSNotFound;
}
return NO;
}
This code works perfect. Good luck! If something is not clear, please let me know.:)