I have a problem with UISearchController, it is declared in my "FindUsersTableViewController.h" file used to display the searched users.
So, all is in the title, I give you more details with important parts of code of the "FindUsersTableViewController.m" file:
- (void)viewDidLoad {
[super viewDidLoad];
self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchResultsUpdater = self;
self.searchController.delegate = self;
self.searchController.searchBar.frame = CGRectMake(0, 0, 320, 44);
self.tableView.tableHeaderView = self.searchController.searchBar;
self.searchController.searchBar.tintColor = [UIColor blackColor];
self.definesPresentationContext = YES;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.searchResults.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *userCellId = #"userCell";
UserCell *userCell = [tableView dequeueReusableCellWithIdentifier:userCellId forIndexPath:indexPath];
// "self.searchedUser" is a property declared as PFUser in the .h file
PFUser *tempSrchUser = self.searchedUser;
// "self.searchResults" is a property declared as NSMutableArray in the .h file too, it contains the searched users
PFObject *searchedUser = [self.searchResults objectAtIndex:indexPath.row];
NSString *tempUsername = [searchedUser objectForKey:tempSrchUser.username];
userCell.usernameLbl.text = tempUsername;
NSLog(#"retrieved appropriates usernames: %#", userCell.usernameLbl.text);
return userCell;
}
The UISearchController does not display anything... Does anyone knows how to fix that ?
Have you implemented the delegate method - (void)updateSearchResultsForSearchController:(UISearchController *)searchController
? This is required and you need to do the filtering here.
Related
Creating a search view, this is the code that i did for the main search view.
What happens is if i dont search/filter, the uisearchbar gets dismissed when segueing. but if i search/filter then the uisearchbar stays on the nav bar when seguing.
- (void)viewDidLoad {
[super viewDidLoad];
// There's no transition in our storyboard to our search results tableview or navigation controller
// so we'll have to grab it using the instantiateViewControllerWithIdentifier: method
UINavigationController *searchResultsController = [[self storyboard] instantiateViewControllerWithIdentifier:#"CompanySearchResultsNavigationController"];
// Our instance of UISearchController will use searchResults
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
// The searchcontroller's searchResultsUpdater property will contain our tableView.
self.searchController.searchResultsUpdater = self;
self.searchController.hidesNavigationBarDuringPresentation = NO;
// The searchBar contained in XCode's storyboard is a leftover from UISearchDisplayController.
// Don't use this. Instead, we'll create the searchBar programatically.
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.navigationItem.titleView = self.searchController.searchBar;
self.definesPresentationContext = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.objects count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
CompanySearchTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"searchCell" forIndexPath:indexPath];
cell.productImageView.file = (PFFile *)object[#"profileImage"];
cell.productImageView.layer.cornerRadius = cell.productImageView.frame.size.width / 2;
cell.productImageView.clipsToBounds = YES;
[cell.productImageView loadInBackground];
cell.companyNameLabel.text = object[#"username"];
return cell;
}
#pragma mark - UISearchControllerDelegate & UISearchResultsDelegate
// Called when the search bar becomes first responder
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
// Set searchString equal to what's typed into the searchbar
NSString *searchString = self.searchController.searchBar.text;
[self updateFilteredContentForAirlineName:searchString];
// If searchResultsController
if (self.searchController.searchResultsController) {
UINavigationController *navController = (UINavigationController *)self.searchController.searchResultsController;
// Present SearchResultsTableViewController as the topViewController
CompanySearchResultsTableViewController *vc = (CompanySearchResultsTableViewController *)navController.topViewController;
// Update searchResults
vc.searchResults = self.searchResults;
// And reload the tableView with the new data
[vc.tableView reloadData];
}
}
// Update self.searchResults based on searchString, which is the argument in passed to this method
- (void)updateFilteredContentForAirlineName:(NSString *)companyName
{
if (companyName == nil) {
// If empty the search results are the same as the original data
self.searchResults = [self.objects mutableCopy];
} else {
NSMutableArray *searchResults = [[NSMutableArray alloc] init];
// Else if the airline's name is
for (PFObject *company in self.objects) {
if ([company[#"username"] containsString:companyName]) {
// NSString *str = [NSString stringWithFormat:#"%#", company[#"username"]];
// [searchResults addObject:str];
PFObject *searchedObject = company;
[searchResults addObject:searchedObject];
NSLog(#"Searched: %#",searchedObject[#"username"]);
}
self.searchResults = searchResults;
}
}
}
In your AirlineTableViewController, override [UIViewController prepareForSegue]:
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender {
[self.searchController setActive:NO];
}
Not sure if the title makes to much sense so here is a description of what is going on:
I have a UITableViewController that is using a custom UITableViewCell for its data. I am then manually adding a searchBar to the header of the UITableView and setting it up based on this tutorial : http://useyourloaf.com
Now the searchBar is setup, it looks like it is working but the issue is that I am not actually getting any results and the table is not loading properly (the search results, it load the base data fine)
Here is my code for comparison. I know I must be missing something simple...
** I am hardcoding the data for my cells at the moment, this will change to a core data model once I can fix this issue... although this may be the base of my issue as I am hardcoding the cells at each IP **
#implementation CharitiesTableViewController{
NSArray *charities;
NSArray *searchResults;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setColors];
[_charityTable registerNib:[UINib nibWithNibName:#"CharityTableViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"charityCell"];
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 350.0;
// self.tableView.contentInset = UIEdgeInsetsMake(-2.0f, 0.0f, 0.0f, 0.0);
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.delegate = self;
self.searchController.delegate = self;
self.tableView.tableHeaderView = self.searchController.searchBar;
self.definesPresentationContext = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void) setColors {
}
#pragma mark - Search Controller
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
NSString *searchString = searchController.searchBar.text;
[self searchForText:searchString];
[self.tableView reloadData];
}
- (void)searchForText:(NSString *)searchText {
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
searchResults = [charities filteredArrayUsingPredicate:resultPredicate];
}
- (void)willPresentSearchController:(UISearchController *)searchController {
self.navigationController.navigationBar.translucent = YES;
}
-(void)willDismissSearchController:(UISearchController *)searchController {
self.navigationController.navigationBar.translucent = NO;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (tableView == _charityTable)
{
return 1;
}
return [searchResults count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section {
return SectionSpacer;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return SectionSpacer;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section) {
case 0:{
CharityTableViewCell *cell = (CharityTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"charityCell"];
cell.charityImage.image = [UIImage imageNamed:#"cleanup"];
cell.charityName.text = #"Garbage cleanup - Crowchild";
cell.charityTagLine.text = #"City of Calgary";
cell.charityDescriptionShort.text = #"We are rounding up anyone that wants to help clean up the grass and nearby areas close to crowchild.";
return cell;
}
default:{
UITableViewCell *cell;
return cell;
}
}
}
#end
Thanks for you help!
I am silly.... I was trying to do this without initializing the data like a com mentor said. The code is correct and if anyone has any similar issues make sure your array of data actually has data in it...
I am having this weird side effect when I use a UISearchController to update my table view (If I select something from the tableview without searching the bug doesn't manifest itself). But when I search, select a cell, and then popViewControllerAnimated: for some reason the NavigationBar is no longer hidden. I want to think that this is a bug within iOS and not specific to my code. But I thought I would see if anyone can spot a bug in my code or has any ideas of something I might be doing wrong. I've added [self.navigationController setNavigationBarHidden:YES]; to my viewWillAppear of the rootView but the bar doesn't go away until the animation is over.
My TableView/UISearchController code:
#interface LBSelectUniversityView()<UISearchResultsUpdating, UISearchBarDelegate>
#property (strong, nonatomic) UISearchController *searchController;
#end
#implementation LBSelectUniversityView {
NSArray *schoolNames;
NSArray *searchResults;
}
- (void)viewDidLoad {
[super viewDidLoad];
schoolNames = [[LBUtilities sharedInstance] schoolNames];
searchResults = schoolNames;
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];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return searchResults.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];
}
...
return cell;
}
- (void)filterContentForSearchText:(NSString*)searchText{
if ([searchText isEqualToString:#""]) return;
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
searchResults = [schoolNames filteredArrayUsingPredicate:resultPredicate];
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController{
NSString *searchString = searchController.searchBar.text;
[self filterContentForSearchText:searchString];
[self.tableView reloadData];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
...
[self.navigationController popViewControllerAnimated:YES];
}
#end
Does the problem go away if you set searchController.hidesNavigationBarDuringPresentation = NO?
Maybe the following is happening:
When you start searching, searchController.active is set to YES. Thus searchController calls [... setNavigationBarHidden:YES] because UISearchController.hidesNavigationBarDuringPresentation = YES by default.
popViewControllerAnimated: is called.
searchController.active is set to NO, so searchController calls [... setNavigationBarHidden:NO]. This causes the navigation bar to be shown.
I think once your search results comes back you are reloading your main table and not search table. This is how you should load data on search results table.
self.searchController.searchResultsTableView reloadData];
I am trying to gain some knowledge on UISearchDisplayController and going through some tutorial with examples, I have the below class ready with a search bar and table view with data on it.
Header file:
#import <UIKit/UIKit.h>
#interface MyClass : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate, UISearchBarDelegate>
#property (nonatomic, strong) IBOutlet UITableView *suggestionsTableView;
#property (nonatomic, strong) IBOutlet UISearchBar *searchBar;
#end
Implementation file:
#import "MyClass.h"
#interface DVWNoteTypeSuggestionDisplayController ()
#property (nonatomic, strong) NSArray *items;
#property (nonatomic)BOOL isSearching;
#property (nonatomic, strong) NSMutableArray *filteredList;
#end
#implementation MyClass
- (id)init
{
self = [super initWithNibName:#"SuggestionDisplayController" bundle:BUNDLE];
if (self)
{
// Set the title.
self.title = #"test";
}
return self;
}
- (void)viewDidLoad
{
self.searchBar = [[UISearchBar alloc] init];
[[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchDisplayController.searchResultsDelegate = self;
self.searchDisplayController.searchResultsDataSource = self;
self.searchDisplayController.delegate = self;
self.searchBar.frame = CGRectMake(0, 0, 0, 38);
self.suggestionsTableView.tableHeaderView = self.searchBar;
self.items = [[NSArray alloc] initWithObjects:#"Item No. 1", #"Item No. 2", #"Item No. 3", #"Item No. 4", #"Item No. 5", #"Item No. 6", nil];
self.isSearching = NO;
self.filteredList = [[NSMutableArray alloc] init];
}
#pragma mark - Table view data source
- (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.
// // Usually the number of items in your array (the one that holds your list)
// return [self.items count];
//}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (self.isSearching)
{
//If the user is searching, use the list in our filteredList array.
return [self.filteredList count];
} else
{
return [self.items count];
}
}
//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// //Where we configure the cell in each row
//
// static NSString *CellIdentifier = #"Cell";
// UITableViewCell *cell;
//
// cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// if (cell == nil) {
// cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// }
// // Configure the cell... setting the text of our cell's label
// cell.textLabel.text = [self.items objectAtIndex:indexPath.row];
// return cell;
//}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSString *title;
if (self.isSearching && [self.filteredList count]) {
//If the user is searching, use the list in our filteredList array.
title = [self.filteredList objectAtIndex:indexPath.row];
} else
{
title = [self.items objectAtIndex:indexPath.row];
}
cell.textLabel.text = title;
return cell;
}
- (void)filterListForSearchText:(NSString *)searchText
{
[self.filteredList removeAllObjects]; //clears the array from all the string objects it might contain from the previous searches
for (NSString *title in self.items) {
NSRange nameRange = [title rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (nameRange.location != NSNotFound) {
[self.filteredList addObject:title];
}
}
}
#pragma mark - UISearchDisplayControllerDelegate
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
//When the user taps the search bar, this means that the controller will begin searching.
self.isSearching = YES;
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
//When the user taps the Cancel Button, or anywhere aside from the view.
self.isSearching = NO;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterListForSearchText:searchString]; // The method we made in step 7
// Return YES to cause the search result table view to be reloaded.
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
[self filterListForSearchText:[self.searchDisplayController.searchBar text]]; // The method we made in step 7
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#end
Whenever I try to search for any items in the data set (eg: "Item No. 5") its not hitting the breakpoints on any of the delegate i.e. actually the search is not working. Please suggest what am I missing here as this is just my learning project right now.
It appears that a UISearchDisplayController created programatically in this way is prematurely zeroing the delegate, even though the view controller is retaining the UISearchDisplayController as expected.
Add the following to the end of your viewDidLoad and you'll see that the first log will be a valid object, but the second will be null.
NSLog(#"Delegate should be %#", self.searchDisplayController.delegate);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(#"Delegate is %#", self.searchDisplayController.delegate);
});
The quickest way I've found to get around this is to store your own reference to the UISearchDisplayController via a private property or ivar.
If you have to create object for search bar controller and set delegate search bar its work.
UISearchBar *searchBar = [[UISearchBar alloc] init];
[[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
self.searchDisplayController.searchResultsDelegate = self;
self.searchDisplayController.searchResultsDataSource = self;
self.searchDisplayController.delegate = self;
searchBar.frame = CGRectMake(0, 0, 0, 38);
self.tableView.tableHeaderView = searchBar;
I am stucked in this problem for many hours and have n't found any solution on SO...
I have got a table as a subview in UIViewController. When view loads, all datasource methods are called for tableview, but as I receive data from server and call [someTable reloadData], none of the data source methods are called. I have confirmed through breakpoints that my array do contains 100 objects. Also both delegate and datasource are bind to File owner in IB.
What can be possibly missing ? Please help me... Thanks :(
OutLogController.h
#interface OutLogController : UIViewController<UITableViewDataSource,UITableViewDelegate,ASIHTTPRequestDelegate>
{
NSMutableArray *outstandingKeys;
}
#property (strong, nonatomic) IBOutlet UITableView *someTable;
#end
OutLogController.m
#interface OutLogController ()
#end
#implementation OutLogController
#synthesize someTable;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
outstandingKeys = [[NSMutableArray alloc] init];
someTable = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
someTable.rowHeight = 85;
[self retrieveOutstandingLogFromServer];
}
- (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.
return outstandingKeys.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...
LogUnit *unit = [outstandingKeys objectAtIndex:indexPath.row];
cell.textLabel.text = unit.symbol;
return cell;
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 85;
}
-(void) requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"%#",request.responseString);
NSArray *list = [request.responseString JSONValue];//contains 100 objects
for (int i = 0; i < list.count; i++) {
NSArray *singleTrade = [[list objectAtIndex:i] JSONValue];
LogUnit *unit = [[LogUnit alloc] init];
unit.symbol = [singleTrade objectAtIndex:0];
unit.type = [singleTrade objectAtIndex:1];
unit.price = [singleTrade objectAtIndex:2];
unit.remaining = [singleTrade objectAtIndex:3];
unit.order = [singleTrade objectAtIndex:4];
unit.time = [singleTrade objectAtIndex:5];
[outstandingKeys addObject:unit];
}
if(outstandingKeys.count > 0)
{
[someTable reloadData];//does reload table
}
}
EDIT
After removing line:
someTable = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
Datasource methods are called except cellForRowAtIndexPath and table disappears from view since this method is not called. Any idea why it can't get called?
Note: I have confirmed that I have count = 100 after response from server.
someTable = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
You have already bind your UITableView from nib/storyboard. In this case you did not have to alloc again the tableview. Removing this line will do the work
someTable = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
You create new tableView and it doesn't add to current view.
check your outstandingKeys Count may it zero count
Try to reload data by performing it on main thread..
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableRating reloadData];
});
This will solve your problem. Happy Coding..