How do I use the UISearchBar and UISearchDisplayController
- First add the UISearchDisplayController to your table view
- Then set its delegate.
- Implement the following methods.
Demo Project
In your .h File
@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
NSMutableArray *contentList;
NSMutableArray *filteredContentList;
BOOL isSearching;
}
@property (strong, nonatomic) IBOutlet UITableView *tblContentList;
@property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
@property (strong, nonatomic) IBOutlet UISearchDisplayController *searchBarController;
In your .m File
Filling the sample data (Optional Only For Demo Purpose)
- (void)viewDidLoad {
[super viewDidLoad];
contentList = [[NSMutableArray alloc] initWithObjects:@"iPhone", @"iPod", @"iPod touch", @"iMac", @"Mac Pro", @"iBook",@"MacBook", @"MacBook Pro", @"PowerBook", nil];
filteredContentList = [[NSMutableArray alloc] init];
}
Now implement the Table View Delegate and Datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
if (isSearching) {
return [filteredContentList count];
}
else {
return [contentList count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
if (isSearching) {
cell.textLabel.text = [filteredContentList objectAtIndex:indexPath.row];
}
else {
cell.textLabel.text = [contentList objectAtIndex:indexPath.row];
}
return cell;
}
Search Function Responsible For Searching
- (void)searchTableList {
NSString *searchString = searchBar.text;
for (NSString *tempStr in contentList) {
NSComparisonResult result = [tempStr compare:searchString options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchString length])];
if (result == NSOrderedSame) {
[filteredContentList addObject:tempStr];
}
}
}
Search Bar Implementation
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
isSearching = YES;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(@"Text change - %d",isSearching);
//Remove all objects first.
[filteredContentList removeAllObjects];
if([searchText length] != 0) {
isSearching = YES;
[self searchTableList];
}
else {
isSearching = NO;
}
// [self.tblContentList reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
NSLog(@"Cancel clicked");
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSLog(@"Search Clicked");
[self searchTableList];
}
How UISearchDisplayController steals UISearchBar events
OK, I figured out myself.
You can do that just by adding the UISearchBar delegate property to KVO observation, and then make your implementation as a delegate proxy.
Example Code:
if (searchBar.delegate) {
self.searchBarDelegate = searchBar.delegate;
}
searchBar.delegate = self;
[searchBar addObserver:self forKeyPath:@"delegate" options:NSKeyValueObservingOptionNew context:kSearchBarKVOContext];
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == kSearchBarKVOContext) {
[self updateSearchBarDelegate];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)updateSearchBarDelegate
{
if (self.searchBar.delegate == self) {
self.searchBarDelegate = nil;
} else {
self.searchBarDelegate = self.searchBar.delegate;
self.searchBar.delegate = self;
}
}
#pragma mark - NSObject Overrides
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *result = [super methodSignatureForSelector:aSelector];
if (!result) {
NSObject *obj = (NSObject *)self.searchBarDelegate;
result = [obj methodSignatureForSelector:aSelector];
}
return result;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([self.searchBarDelegate respondsToSelector:[anInvocation selector]]) {
[anInvocation invokeWithTarget:self.searchBarDelegate];
} else {
[super forwardInvocation:anInvocation];
}
}
- (BOOL)respondsToSelector:(SEL)aSelector {
return ([super respondsToSelector:aSelector] ||
[self.searchBarDelegate respondsToSelector:aSelector]);
}
How to use UISearchDisplayController from a controller within an UITabBar controller?
Ok, I have found how to solve it. In my case, the problem was due to the fact that I was using a controller embedded within the UITabBarController as one of its managed tabs (i.e. as a child).
Removing the controller from the UITabBarController, then adding an UINavigationController to the UITabBarController instead, and finally putting my controller as a child of the UINavigationController solved completely the issue.
I do not understand why this is so (there is no related information in the documentation, as often happens); however, it now works like a charm.
With kind regards.
Related Topics
iOS Getting Location Updates When App Terminated Without Using Significantchange
Turn a Page Like a Book with Uiview
Transition Animation Not Working in Swiftui
How to Set Initial Values for Nsuserdefault Keys
Where and When to Get Data for Watch Complication
Blocks on Swift (Animatewithduration:Animations:Completion:)
Didupdatelocations Instead of Didupdatetolocation
Swift Protocol Get Only Settable
iOS - Integrating Credit Card Payments
How to Create Static Library and Can Add Just .A File on Any Project in iOS
How to Programmatically Use iOS Voice Synthesizers? (Text to Speech)
Uicollectionview with Paging - Setting Page Width