Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialRyan Heybourn
314 PointsHow to implement search function in Ribbit app?
Hi All,
I have created the Ribbit app, following Ben's helpful tutorial. And I had a few ideas to add to it.
Instead of users having to scroll through everyone who is on my apps database, just to find one person, I would like to have a search feature. This would mean, upon tapping 'edit' on the friends screen, the user could then tap in a search bar, and find the person they are looking for. No users would appear before the search, everyone else who is listed on the database would appear invisible (if that makes sense?) So, only the user that has that name, would appear in their search results, not the whole database.
How would i go about implementing this?
Cheers, Ryan
16 Answers
Stone Preston
42,016 Pointsin your add friends view controller, you would need to drag a search bar onto your view in the header portion of the table view. Make sure you set that the bar has a cancel button in the attributes inspector. Then in your header file you would have to conform to the UISearchBarDelegateProtocol
: UITableViewController <UISearchBarDelegate>
You also need to add that search bar you dragged onto the view as a property as well as a PFObject property to hold the user that is found.
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
@property (strong, nonatomic) PFObject *user;
set the search bar delegate in view did load
self.searchBar.delegate = self;
and implement these methods
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
//dismiss keyboard
[self.searchBar resignFirstResponder];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
//Enable the cancel button when the user touches the search field
self.searchBar.showsCancelButton = TRUE;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
//dsiable the cancel button when the user ends editing
self.searchBar.showsCancelButton = FALSE;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
//dismiss keyboard
[self.searchBar resignFirstResponder];
//Strip the whitespace off the end of the search text
NSString *searchText = [self.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//Check to make sure the field isnt empty and Query parse for username in the text field
if (![searchText isEqualToString:@""]) {
PFQuery *query = [PFUser query];
[query whereKey:@"username" equalTo:searchText];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
//check to make sure the query actually found a user
if (objects.count > 0) {
//found a user
self.user = [objects objectAtIndex:0];
//A user was not found, display error message
} else {
//no user found
}
[self.tableView reloadData];
} else {
//error occurred
}
}];
}
}
you would also need to make sure your tableView delegate methods use the same self.user property you set in the query block (as opposed to self.allUsers)
As far as making the table view empty when the view appears just set the data source to nil in viewWillAppear. That will clear out the data anytime the view appears so you get a blank view when it appears, when you search and find a user the tableview shows that user, and when it appears again its blank again.
Ryan Heybourn
314 PointsThank you!
Stone Preston
42,016 Pointsno problem.
hello world
346 PointsHi I'm adding this to the editViewController. But I get an error on: - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
Any good tips what Im doing wrong?
Stone Preston
42,016 Pointswhat error did you get?
hello world
346 PointsThanks for looking in to it. Helping a noob out:)
Ok. So I don't remove anything from the editViewController that was made with ribbit. I just add your code to the .h and .m file. Maybe I'm doing it wrong?
See errors below.
1) Error:
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
Issue: Use of undeclared identifier 'searchBarCancelButton Clicked
2) Error: PFQuery *query = [PFUser query]; [query orderByAscending:@"username"]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { if (error) { NSLog(@"Error: %@ %@", error, [error userInfo]); } else { self.allUsers = objects; [self.tableView reloadData]; } }];
Issue:
- Use of undeclared identifier 'query'
- Use of undeclared identifier 'query'
This issue is marked over: [query orderByAscending:@"username"]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
Stone Preston
42,016 Pointsyou didnt conform to the UISearchBar delegate protocol
: UITableViewController <UISearchBarDelegate>
hello world
346 PointsHow do I do that:) I added it in header file. Should I do it in the .m file too?
Stone Preston
42,016 Pointsjust the header. paste the code you used to do that. you may have used searchBarControllerDelegate instead of searchBarDelegate
hello world
346 PointsThe full code .h file:
import <UIKit/UIKit.h>
import <Parse/Parse.h>
@interface EditFavoritesViewController : UITableViewController <UISearchBarDelegate> @property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
@property (nonatomic, strong) NSArray *allUsers; @property (nonatomic, strong) PFUser *currentUser; @property (nonatomic, strong) NSMutableArray *friends;
- (BOOL)isFriend:(PFUser *)user;
@end
The full code .m file:
import "EditFavoritesViewController.h"
@interface EditFavoritesViewController ()
@end
@implementation EditFavoritesViewController
-
(void)viewDidLoad { [super viewDidLoad];
self.searchBar.delegate = self;
-
(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
//dismiss keyboard [self.searchBar resignFirstResponder];
}
-
(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
//Enable the cancel button when the user touches the search field self.searchBar.showsCancelButton = TRUE; }
-
(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
//dsiable the cancel button when the user ends editing self.searchBar.showsCancelButton = FALSE; }
-
(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
//dismiss keyboard [self.searchBar resignFirstResponder];
//Strip the whitespace off the end of the search text NSString *searchText = [self.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//Check to make sure the field isnt empty and Query parse for username in the text field if (![searchText isEqualToString:@""]) {
PFQuery *query = [PFUser query]; [query whereKey:@"username" equalTo:searchText]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { if (!error) { //check to make sure the query actually found a user if (objects.count > 0) { //found a user //set the user as the table views data source and reload the table view //A user was not found, display error message } else { //no user found } [self.tableView reloadData]; } else { //error occurred } }];
}
}
PFQuery *query = [PFUser query]; [query orderByAscending:@"username"]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { if (error) { NSLog(@"Error: %@ %@", error, [error userInfo]); } else { self.allUsers = objects; [self.tableView reloadData]; } }];
self.currentUser = [PFUser currentUser]; }
-
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. return [self.allUsers count]; }
-
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFUser *user = [self.allUsers objectAtIndex:indexPath.row]; cell.textLabel.text = user.username;
if ([self isFriend:user]) { cell.accessoryType = UITableViewCellAccessoryCheckmark; } else { cell.accessoryType = UITableViewCellAccessoryNone; }
return cell; }
pragma mark - Table view delegate
-
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
PFRelation *friendsRelation = [self.currentUser relationforKey:@"friendsRelation"]; PFUser *user = [self.allUsers objectAtIndex:indexPath.row];
if ([self isFriend:user]) { cell.accessoryType = UITableViewCellAccessoryNone;
for(PFUser *friend in self.friends) { if ([friend.objectId isEqualToString:user.objectId]) { [self.friends removeObject:friend]; break; } } [friendsRelation removeObject:user];
} else { cell.accessoryType = UITableViewCellAccessoryCheckmark; [self.friends addObject:user]; [friendsRelation addObject:user]; }
[self.currentUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { if (error) { NSLog(@"Error: %@ %@", error, [error userInfo]); } }]; }
pragma mark - Helper methods
-
(BOOL)isFriend:(PFUser *)user { for(PFUser *friend in self.friends) { if ([friend.objectId isEqualToString:user.objectId]) { return YES; } }
return NO; }
@end
hello world
346 PointsUps. Don't know if that makes sense. On import it should say Parse/Parse.h and UIKit/UIKit.h in .h file
Stone Preston
42,016 Pointsyou will need to format that using markdown. some of your code is missing since its not marked down
hello world
346 PointsSorry but how do i do that :(
Stone Preston
42,016 Pointsat the bottom right of the comment textbox there is a link that says Markdown Cheatsheet
hello world
346 PointsThanks:) Ok. Does it matter what type of search bar you drag in to the .h file as a property?
// EditFavoritesViewController.h
<p>#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
@interface EditFavoritesViewController : UITableViewController <UISearchBarDelegate>
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
@property (nonatomic, strong) NSArray *allUsers;
@property (nonatomic, strong) PFUser *currentUser;
@property (nonatomic, strong) NSMutableArray *friends;
- (BOOL)isFriend:(PFUser *)user;
@end
</p>
```
// EditFavoritesViewController.m
```html
<p>#import "EditFavoritesViewController.h"
@interface EditFavoritesViewController ()
@end
@implementation EditFavoritesViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchBar.delegate = self;
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
//dismiss keyboard
[self.searchBar resignFirstResponder];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
//Enable the cancel button when the user touches the search field
self.searchBar.showsCancelButton = TRUE;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
//dsiable the cancel button when the user ends editing
self.searchBar.showsCancelButton = FALSE;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
//dismiss keyboard
[self.searchBar resignFirstResponder];
//Strip the whitespace off the end of the search text
NSString *searchText = [self.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//Check to make sure the field isnt empty and Query parse for username in the text field
if (![searchText isEqualToString:@""]) {
PFQuery *query = [PFUser query];
[query whereKey:@"username" equalTo:searchText];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
//check to make sure the query actually found a user
if (objects.count > 0) {
//found a user
//set the user as the table views data source and reload the table view
//A user was not found, display error message
} else {
//no user found
}
[self.tableView reloadData];
} else {
//error occurred
}
}];
}
}
PFQuery *query = [PFUser query];
[query orderByAscending:@"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"Error: %@ %@", error, [error userInfo]);
}
else {
self.allUsers = objects;
[self.tableView reloadData];
}
}];
self.currentUser = [PFUser currentUser];
}
#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.
return [self.allUsers count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFUser *user = [self.allUsers objectAtIndex:indexPath.row];
cell.textLabel.text = user.username;
if ([self isFriend:user]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
PFRelation *friendsRelation = [self.currentUser relationforKey:@"friendsRelation"];
PFUser *user = [self.allUsers objectAtIndex:indexPath.row];
if ([self isFriend:user]) {
cell.accessoryType = UITableViewCellAccessoryNone;
for(PFUser *friend in self.friends) {
if ([friend.objectId isEqualToString:user.objectId]) {
[self.friends removeObject:friend];
break;
}
}
[friendsRelation removeObject:user];
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.friends addObject:user];
[friendsRelation addObject:user];
}
[self.currentUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(@"Error: %@ %@", error, [error userInfo]);
}
}];
}
#pragma mark - Helper methods
- (BOOL)isFriend:(PFUser *)user {
for(PFUser *friend in self.friends) {
if ([friend.objectId isEqualToString:user.objectId]) {
return YES;
}
}
return NO;
}
@end</p>
```
Stone Preston
42,016 Pointshmm your code looks good so im not really sure whats going on
hello world
346 PointsCould it be that i targeting ios7?
Stone Preston
42,016 Pointsno im targetings ios 7 as well and it works fine
hello world
346 PointsOk...Thanks anyway man! So it can't be a problem of what type of search bar I use?
hello world
346 PointsDid you use Parse Query Table setup?
hello world
346 PointsBen Jakuben
Treehouse TeacherSorry I missed this, helloworld! Is it still an issue? The code you posted looks okay. If it's still a problem, let's start a new thread. Tag me in the new one so I get a notification.
hello world
346 Points:(
Fuseini Isaac
Courses Plus Student 2,225 Pointscan you help for android?
Ben Jakuben
Treehouse TeacherHi Fuseini Isaac, post a new question for Android and add some specific details and we can try to help.
POKE !
88 PointsHi Ben Jakuben
I have the same problem with this code. It dosent find any user when I search
<p>#import "FindViewController.h"
#import "FindDetailsViewController.h"
#import "FindCell.h"
@interface FindViewController ()
@end
@implementation FindViewController {
//
CLLocationManager *locationManager;
}
@synthesize currentGeoPoint;
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
//Sök
self.searchBar.delegate = self;
//Hittar GeoLocation för telefonen
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
NSLog(@"%@", [self deviceLocation]);
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.opaque = NO;
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"berg.jpg"]];
self.navigationItem.hidesBackButton = YES;
UIImage *image = [UIImage imageNamed: @"Invest.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage: image];
self.navigationItem.titleView = imageView;
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.opaque = NO;
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"berg.jpg"]];
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(refreshTable:)
name:@"refreshTable"
object:nil];
}
- (NSString *)deviceLocation {
return [NSString stringWithFormat:@"latitude: %f longitude: %f", locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude];
}
- (void)refreshTable:(NSNotification *) notification
{
// Reload the recipes
[self loadObjects];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"refreshTable" object:nil];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)loadObjects
{
if (!self.currentGeoPoint)
{
[PFGeoPoint geoPointForCurrentLocationInBackground:^(PFGeoPoint *geo, NSError *error)
{
self.currentGeoPoint = geo;
[super loadObjects];
}];
}
else
{
[super loadObjects];
}
}
- (PFQuery *)queryForTable
{
PFQuery *query = [PFUser query];
query.limit = 3;
[query whereKey:@"money" equalTo: [NSNumber numberWithBool:TRUE]];
[query whereKey:@"currentLocation" nearGeoPoint:self.currentGeoPoint withinKilometers:20];
return query;
self.pullToRefreshEnabled = YES;
// Whether the built-in pagination is enabled
self.paginationEnabled = NO;
// The number of objects to show per page
self.objectsPerPage = 10;
return query;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *simpleTableIdentifier = @"FindCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
// Configure the cell
PFFile *thumbnail = [object objectForKey:@"profileimageFile"];
PFImageView *thumbnailImageView = (PFImageView*)[cell viewWithTag:100];
thumbnailImageView.image = [UIImage imageNamed:@"placeholder2.jpg"];
thumbnailImageView.file = thumbnail;
[thumbnailImageView loadInBackground];
UILabel *nameLabel = (UILabel*) [cell viewWithTag:101];
nameLabel.text = [object objectForKey:@"name"];
UILabel *prepTimeLabel = (UILabel*) [cell viewWithTag:102];
prepTimeLabel.text = [object objectForKey:@"title"];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
- (void) objectsDidLoad:(NSError *)error
{
[super objectsDidLoad:error];
NSLog(@"error: %@", [error localizedDescription]);
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"showFindDetails"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
FindDetailsViewController *destViewController = segue.destinationViewController;
PFObject *object = [self.objects objectAtIndex:indexPath.row];
FindCell *find = [[FindCell alloc] init];
find.name = [object objectForKey:@"name"];
find.imageFile = [object objectForKey:@"profileimageFile"];
find.prepTime = [object objectForKey:@"title"];
find.location = [object objectForKey:@"location"];
find.ingredients = [object objectForKey:@"moneyProfile"];
destViewController.find= find;
}
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
//dismiss keyboard
[self.searchBar resignFirstResponder];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
//Enable the cancel button when the user touches the search field
self.searchBar.showsCancelButton = TRUE;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
//dsiable the cancel button when the user ends editing
self.searchBar.showsCancelButton = FALSE;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
//dismiss keyboard
[self.searchBar resignFirstResponder];
//Strip the whitespace off the end of the search text
NSString *searchText = [self.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//Check to make sure the field isnt empty and Query parse for username in the text field
if (![searchText isEqualToString:@""]) {
PFQuery *query = [PFUser query];
[query whereKey:@"username" equalTo:searchText];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
//check to make sure the query actually found a user
if (objects.count > 0) {
//found a user
//set the user as the table views data source and reload the table view
//A user was not found, display error message
} else {
//no user found
}
[self.tableView reloadData];
} else {
//error occurred
}
}];
}
}
@end</p>
```