UISearchBar displays no results while typing in text - ios

When my user searches an item in my UISearchBar, results are displayed if the full word typed into the bar matches one of the results. E.g. if "Panda" is typed in, Panda pops up in the tableView results. However if "Pan" is typed in, no results are shown. How can I make my search results filter work as the user is typing? Panda should be displayed even if just "pan" is typed in.
My filter code currently looks like this:
.m
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
}
/*
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
} */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchResults count];
} else {
return [self.neighbourData count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *NetworkTableIdentifier = #"sidebarCell";
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
sidebarCell *cell = (sidebarCell *)[tableView dequeueReusableCellWithIdentifier:NetworkTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"sidebarCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
NSDictionary *userName = [searchResults objectAtIndex:indexPath.row];
[[cell username] setText:[userName objectForKey:#"first name"]];
NSDictionary *userlast = [searchResults objectAtIndex:indexPath.row];
[[cell lastName] setText:[userlast objectForKey:#"last name"]];
NSDictionary *userBio = [searchResults objectAtIndex:indexPath.row];
[[cell userDescription] setText:[userBio objectForKey:#"userbio"]];
NSString *profilePath = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"photo_path"];
[cell.usermini sd_setImageWithURL:[NSURL URLWithString:profilePath]];
NSLog(#"This is profilePath %#",profilePath);
} else {
NSDictionary *userName = [self.neighbourData objectAtIndex:indexPath.row];
[[cell username] setText:[userName objectForKey:#"first name"]];
NSDictionary *userlast = [self.neighbourData objectAtIndex:indexPath.row];
[[cell lastName] setText:[userlast objectForKey:#"last name"]];
NSDictionary *userBio = [self.neighbourData objectAtIndex:indexPath.row];
[[cell userDescription] setText:[userBio objectForKey:#"userbio"]];
NSString *profilePath = [[self.neighbourData objectAtIndex:indexPath.row] objectForKey:#"photo_path"];
[cell.usermini sd_setImageWithURL:[NSURL URLWithString:profilePath]];
NSLog(#"This is profilePath %#",profilePath);
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 115;
}
neighbourData Log:
[12663:3559832] This is the neighbourdata (
{
address = "1144 fake street";
city = Las Vegas;
"first name" = Panda;
"last name" = Zoo;
"photo_path" = "none";
}

try this
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate * predicate =[NSPredicate predicateWithFormat:#"%K contains[cd] %#",#"first name", searchText];
searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
if searchResults.count == 0
{
NSPredicate * predicate =[NSPredicate predicateWithFormat:#"%K contains[cd] %#",#"last name",searchText];
searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
}
// add predicates for other keys also if you want
[tableView reloadData];
}
Suggestions:
Avoid spaces between words of keys ('first name' this is not recommended, 'firstName' recommended)
And save values in all lowercase ('Panda', 'Zoo' its better to save as 'panda','zoo' this will make search more simpler)

You need to reload your tableview after your data filtered and also remove exist object for searchResult array.
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate * predicate =[NSPredicate predicateWithFormat:#"first name = %#", searchText];
searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
[tableView reloadData];
}

Try out this predicate block:
NSPredicate* p = [NSPredicate predicateWithBlock:
^BOOL(id obj, NSDictionary *d) {
NSString* s = obj;
NSStringCompareOptions options = NSCaseInsensitiveSearch;
return ([s rangeOfString:sbc.searchBar.text
options:options].location != NSNotFound);
}];
self.filteredStates = [states filteredArrayUsingPredicate:p];
Meanwhile checkout this Link.
Hope it helps.

The method "filterContentForSearchText" should be in "textDidChange" method of UISearchBar. Where are you writing this method currently?
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
#interface ViewController : UIViewController <UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource, UISearchDisplayDelegate, UISearchBarDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.neighbourData = #[#"Apple", #"App", #"Bell"];
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"filterCell"];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
self.searchResults = [self.neighbourData filteredArrayUsingPredicate:resultPredicate];
}
/*
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
} */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [self.searchResults count];
} else {
return [self.neighbourData count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"filterCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"filterCell"];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel. text = [self.searchResults objectAtIndex:indexPath.row];
} else {
cell.textLabel. text = [self.neighbourData objectAtIndex:indexPath.row];
}
return cell;
#end

Related

display search result in table view in objective-c

I've created a table view with search bar in my View Controller, but the table view doesn't show the search result.
This is how my code working. First i create an Array to hold data >> display the array data in table view >> using search bar to filter the table view.
Here is my code :
- (void)viewDidLoad {
[super viewDidLoad];
self.inventoryarray =[[NSArray alloc] initWithObjects: #"apple",#"samsung",#"HTC",#"LG",#"Sony",#"Motorola",#"Nexus",#"Asus" ,nil];
self.searchresult =[[NSArray alloc]init];
// Do any additional setup after loading the view, typically from a nib.
}
#pragma table View methods
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [self.searchresult count];
} else {
return [self.inventoryarray count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [self.searchresult objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [self.inventoryarray objectAtIndex:indexPath.row];
}
return cell;
}
#pragma search methods
-(void) filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] %#", searchText];
self.searchresult = [self.inventoryarray filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]] ;
return YES;
}
you forget to refesh data on table
-(void) filterContentForSearchText:(NSString *)searchText scope: (NSString *)scope
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
self.searchresult = [self.inventoryarray filteredArrayUsingPredicate:resultPredicate];
// you forget to reload Data
[self.searchDisplayController.searchResultsTableView reloadData];
// else use
[yourtableView reloadData];
}
suggestion : UISearchDisplayController is deprecated, use UISearchController on onwards, for tutorial
You need to only [tableView reloadData]; in last of filterContentForSearchText method.
if you wan't to use UISearchController then...
- 'UISearchDisplayController' is deprecated: first deprecated in iOS 8.0 - UISearchDisplayController has been replaced with UISearchController
if you don't want to use UISearchController then use below method:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {} and reload tableview.

Having trouble showing results of UISearchBar

I am new to iOS development and trying to get help with search result. Everything is working fine but when I search a word, it doesn't show the result so I will be over thanks for your help.. Here is the code..
- (void)viewDidLoad
{
[super viewDidLoad];
mytableview.delegate = self;
mytableview.dataSource = self;
SearchBar.delegate = self;
titleArray = [[NSMutableArray alloc] initWithObjects:#"Arora town",#"Domino pizza ",#"thai hunt",nil];
subtitleArray = [[NSMutableArray alloc] initWithObjects:#"wX<w (rHR< cg)",#"o;vDRuwkR(vXw>csK;cHed;o;wkRtd.tCd)<*kRuhRto; (vXw>urXur.tylR)<o;vDRxl.",nil];
}
here is cellForRowAtIndexPath
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *cellidentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellidentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [self.searchResults objectAtIndex:indexPath.row];
}
else
{
cell.textLabel.text = [titleArray objectAtIndex:indexPath.row];
}
return cell;
}
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", searchText];
self.searchResults = [self.array filteredArrayUsingPredicate:predicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
Try This i Have tested.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView==self.searchDisplayController.searchResultsTableView)
return _results.count;
else
return _countryNames.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier=#"Cell";
UITableViewCell *cell;
cell=[tableView dequeueReusableCellWithIdentifier:identifier];
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [_results objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [_countryNames objectAtIndex:indexPath.row];
}
return cell;
}
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
NSLog(#"%#",scope);
_results = (NSMutableArray *)[_countryNames filteredArrayUsingPredicate:resultPredicate];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
in viewDidLoad
initialize
_results=[[NSMutableArray alloc]init];
_countryNames=[[NSMutableArray alloc] initWithObjects:#"India",#"Pakistan",#"West Indies",#"Zimbabwe", nil];
connect search bar delegate from storyboard.

How to get the correct object when using search controller

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];
}

Terminating App due to'NSInvalidArgumentException'

I am trying to search my array contents from the TableView,The Cells Have Detail View also.When i run my app in stimulator it runs but when i insert objects dynamically and try to search them app crashes with 'NSInvalidArgumentException'.
reason:
'Can't use in/contains operator with collection <customcells: 0x8ea3b40> (not a collection)'.
My code which has Predicates is
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
self.searchedarray = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains [cd] %#", self.searchtext.text];
self.searchedarray =[NSMutableArray arrayWithArray :[contactsarray filteredArrayUsingPredicate:predicate]];
}
and also
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
[searchedarray removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self.name CONTAINS[c] %#", searchText];
searchedarray = [NSMutableArray arrayWithArray:[contactsarray filteredArrayUsingPredicate:predicate]];
}
Help me, I am stuck with this Predicate error ;Using Like instead of contains also doesn't help.
Edited content
- (void)viewDidLoad
{
contactsarray = [[NSMutableArray alloc] init];
self.searchedarray = [NSMutableArray arrayWithCapacity:[contactsarray count]];
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
}
- (void)insertNewObject:(id)sender
{
customcells *new = [[customcells alloc] init];
new.name = #"Enter Name";
new.contacts=#" Enter Contact Number";
new.organisation=#"Enter Organisation Name";
[contactsarray insertObject:new atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (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 (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchedarray count];
} else {
return [contactsarray count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
customcells *myarray= [contactsarray objectAtIndex:indexPath.row];
cell.textLabel.text = myarray.name;
cell.textLabel.text = [NSString stringWithFormat:#"%#",
myarray.name];
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
if (tableView == self.searchDisplayController.searchResultsTableView)
{
customcells *newarray = [searchedarray objectAtIndex:indexPath.row];
cell.textLabel.text =newarray.name;
} else {
customcells *myarray= [contactsarray objectAtIndex:indexPath.row];
cell.textLabel.text = myarray.name;
cell.textLabel.text = [NSString stringWithFormat:#"%#",
myarray.name]; }
}
return cell;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
NSMutableArray *tempContent = [self.contactsarray mutableCopy];
[tempContent removeObject:[tempContent objectAtIndex:indexPath.row]];
self.contactsarray = tempContent;
[tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
self.searchedarray = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains [cd] %#", self.searchtext.text];
self.searchedarray =[NSMutableArray arrayWithArray :[contactsarray filteredArrayUsingPredicate:predicate]];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
customcells *new = contactsarray[indexPath.row];
[[segue destinationViewController] setDetailItem:new];
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
}
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
[searchedarray removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self.name CONTAINS[c] %#", searchText];
searchedarray = [NSMutableArray arrayWithArray:[contactsarray filteredArrayUsingPredicate:predicate]];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// Tells the table data source to reload when text changes
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
// Tells the table data source to reload when scope bar selection changes
[self filterContentForSearchText:self.searchDisplayController.searchBar.text scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#end
Your code is using 'contains' in the NSPredicate, which assumes that each element in your array can be matched using 'contains'. You have an array of customcells, which will not by default have any way of dealing with a contains matcher.
In your second example, using self.name CONTAINS[c] %#, you end up matching on the name property which is a string, so I would expect this to work (though I've not tried it). The first example you give is trying to match on the customcells object directly, so I'd suggest also using self.name in that case as well.

Parse UITableView with Search

I'm following this AppCoda tutorial on implementing Search; however, I'm pulling titles for the table view from Parse and can't get the search function to work. Throws an exception when I start typing in the search:
'Can't use in/contains operator with collection {
buildingLat = "42.726366";
buildingLong = "-84.480642";
buildingTitle = "International Center";
} (not a collection)'
Here's the code for my table view controller:
#import "BuildingsViewController.h"
#import <Parse/Parse.h>
#interface BuildingsViewController ()
#end
#implementation BuildingsViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self performSelector:#selector(retrieveBuildings)];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - TableView Setup
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.buildingsArray count];
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [self.searchResults count];
} else {
return [self.buildingsArray count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"buildingsCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
PFObject *tempObject = [self.buildingsArray objectAtIndex:indexPath.row];
cell.textLabel.text = [tempObject objectForKey:#"buildingTitle"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [self.searchResults objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [tempObject objectForKey:#"buildingTitle"];
}
return cell;
}
#pragma mark - Helper Methods
-(void)retrieveBuildings
{
PFQuery *retrieveBuildings = [PFQuery queryWithClassName:#"buildingsList"];
[retrieveBuildings findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
self.buildingsArray = [[NSArray alloc] initWithArray:objects];
}
[self.tableView reloadData];
}];
}
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF contains[cd] %#",
searchText];
self.searchResults = [self.buildingsArray filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
#end
I think you are on the right track...
My understanding is that you are receiving an array of dictionaries, and passing that received array to your declared buildingsArray. This is not the issue. The issue in my understanding is that you are then attempting to retrieve one of the values from one of those dictionaries without the appropriate code.
Your are attempting this process in two locations.
I refer to the code within your cellForRowAtIndexPath method.
As an aside, it is no longer necessary to check for cell == nil, so you can remove the if statement that wraps your cell setter (cell = [[UITableViewCell...).
UPDATE...
The crash in your code when you remove this check for nil is due to the fact that you do not register a reuse identifier for the searchResultsTableView.
To correct your search and data parsing, I recommend that you follow the sample code I have included following.
Add a new property tempMutableArray, and remove the static declaration from cellForRowAtIndexPath and place it between the #import and #interface lines as shown following...
#import <Parse/Parse.h>
static NSString *CellIdentifier = #"buildingsCell"; // relocated static declaration
#interface BuildingsViewController ()
#property (nonatomic, strong) NSMutableArray *tempMutableArray;
#end
// implementation
Then in your viewDidLoad TVC lifecycle method, instantiate the NSMutableArray, and register the UITableViewCell class and CellIdentifier reuse identifier with searchResultsTableView...
- (void)viewDidLoad {
[super viewDidLoad];
//...your other code...
[self setTempMutableArray:[[NSMutableArray alloc] init]];
[self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:CellIdentifier];
}
...
YOUR NEW REPLACEMENT cellForRowAtIndexPath: METHOD
To properly parse your information from Parse, try the following...
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell = [self.searchDisplayController.searchResultsTableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [self.searchResults objectAtIndex:indexPath.row];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *tempDict = nil;
NSString *tempString = nil;
tempDict = [self.buildingsArray objectAtIndex:indexPath.row];
tempString = [tempDict objectForKey:#"buildingTitle"];
[cell.textLabel setText:tempString];
}
return cell;
}
You will also need to complete similar in your filterContentForSearchText: method.
YOUR NEW REPLACEMENT filterContentForSearchText: METHOD
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = nil;
[self.tempMutableArray removeAllObjects];
for (NSDictionary *tempDict in self.buildingsArray) {
NSString *tempString = nil;
tempString = [tempDict objectForKey:#"buildingTitle"];
[self.tempMutableArray addObject:tempString];
}
resultPredicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] %#", searchText];
self.searchResults = [self.tempMutableArray filteredArrayUsingPredicate:resultPredicate];
}
...CONTINUE WITH PREVIOUS RESPONSE
My understanding... what is happening in your code is that your PFQuery returns an NSArray in its completion block. You set your property buildingsArray, also an NSArray, based on this. Your no longer need, as far as I understand, to treat the returned data as a PFObject.
Let me know how you go.
You are trying to apply the NSPredicate on an array of PFObjects so your predicate needs to look like this:
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"variableNameToSearchOn contains[cd] %#",
searchText];
EDIT:
You can try this:
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"buildingTitle contains[c] %#",
searchText];
#pragma mark UISearchBarDelegate
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
sar.showsCancelButton=YES;
sar.autocorrectionType = UITextAutocorrectionTypeNo;
}
- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSString* newText = [searchBar.text stringByReplacingCharactersInRange:range withString:text];
searchStr = newText;
[self DisplayMatchSearch];
[tblView reloadData];
return YES;
}
-(BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar{
//write code for requset data from database search.....
sar.showsCancelButton=NO;
[sar resignFirstResponder];
return YES;
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
[self getAlldata];
#try {
[tblBeepUsers reloadData];
}
#catch (NSException * e) {
}
[sar resignFirstResponder];
sar.text=#"";
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
searchStr = sar.text;
[sar resignFirstResponder];
[self DisplayMatchSearch];
[tblView reloadData];
}
-(void)DisplayMatchSearch{
if (searchStr && searchStr.length) {
//temp array
arrLocation = [[NSMutableArray alloc] init];
//parsed array self.buildingsArray
for (NSDictionary *dictionary in self.buildingsArray)
{
if ([[dictionary objectForKey:#"name"] rangeOfString:searchStr options:NSCaseInsensitiveSearch].location != NSNotFound) {
[arrLocation addObject:dictionary];
}
}
[tblview reloadData];
}
}

Resources