I have an array of dictionaries where I what to implement search functionality and display data on tableView cells.
Search works quite fine, I have tested it:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSString *dictionryKey = #"eViela";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K CONTAINS [cd] %#", dictionryKey, searchText];
NSArray *filteredArray = [self.allItems filteredArrayUsingPredicate:predicate];
NSLog(#"%#", filteredArray);
self.sortedText = filteredArray;
[self.tableView reloadData];
}
Now I need tableView to fill data only for key "eViela" while user is typing info in search bar. As of now I can show only all items as per below code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SearchCell" forIndexPath:indexPath];
EvielasLibrary *library = [[EvielasLibrary alloc] init];
cell.textLabel.text = [[library.library objectAtIndex:indexPath.row]
return cell;
}
I know that it should be easy but I can't figure it out.
Thanks for help!
You need to get Model from array instead of create new one .
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SearchCell" forIndexPath:indexPath];
EvielasLibrary *library = [self.sortedText objectAtIndex:indexPath.row]; // assume that self.sortedText is your data source array of tableview
cell.textLabel.text = #"" // populate your string here
return cell;
}
NSMutableArray *arrayForTableView = [[NSMutableArray alloc] init];
NSString *dictionryKey = #"eViela";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",dictionryKey];
NSArray *filteredArray = [self.allItems filteredArrayUsingPredicate:predicate];
for (NSInteger i = 0; i<filteredArray.count; i++){
NSString *matchValue = [NSString stringWithFormat:#"%#",[filteredArray objectAtIndex:i]];
if ([matchValue isEqualToString:dictionryKey]){
[arrayForTableView addObject:matchValue];
}
}
Use arrayForTableView array for your tableview
cell.textLabel.text = [arrayForTableView objectAtIndex:indexPath.row];
Problem is that you not updating numberOfRowsInSection delegate method for sortedArray
You need to check if search bar is active or not. if search bar is active then use sortedText array else if search bar is not active then use library.library array
For check search bar active create a global variable isSearchBarActive And assign it true value in searchBarTextDidBeginEditing delegate function and assign false in searchBarTextDidEndEditing
Add Condition in numberOfRowInSection
if searchBarActive {
return self.sortedText.count
}
else {
return library.library.count
}
Add Condition in cellForRowAtIndexPath like this
if searchBarActive {
cell.textLabel.text = [self.sortedText objectAtIndex:indexPath.row]
}
else {
cell.textLabel.text = [library.library objectAtIndex:indexPath.row]
}
Related
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];
}
I have a problem with my search bar I added in my ViewController.
I am getting the following error:
Assertion failure in -[UISearchResultsTableView _configureCellForDisplay:forIndexPath:], /SourceCache/UIKit/UIKit-2935.137/UITableView.m:6509
2014-04-03 18:08:24.355 MyFood[6405:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
configureCell:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// ToDos *toDo = [self.fetchedResultsController objectAtIndexPath:indexPath];
if (viewMode==AlphabeticalOrder) {
Inventory *toDo=nil;
if (self.searchDisplayController.isActive) {
toDo = [searchResults objectAtIndex:indexPath.row];
} else {
toDo=[inventoryProducts objectAtIndex:indexPath.row];
}
cell.textLabel.text = toDo.inventoryProductName;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
NSDate *dt = toDo.expireDate;
NSString *dateAsString = [formatter stringFromDate:dt];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Until: %#", dateAsString];
} else {
Inventory *toDo=nil;
if (self.searchDisplayController.isActive) {
NSDictionary *sectionDict=[searchResults objectAtIndex:indexPath.section];
NSArray *sectionData=[sectionDict objectForKey:#"SECTION_DATA"];
toDo = [sectionData objectAtIndex:indexPath.row];
} else {
NSDictionary *sectionDict=[inventoryProducts objectAtIndex:indexPath.section];
NSArray *sectionData=[sectionDict objectForKey:#"SECTION_DATA"];
toDo=[sectionData objectAtIndex:indexPath.row];
}
cell.textLabel.text = toDo.inventoryProductName;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
NSDate *dt = toDo.expireDate;
NSString *dateAsString = [formatter stringFromDate:dt];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Until: %#", dateAsString];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell.
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
code search bar:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
if (searchText.length!=0) {
if (viewMode==AlphabeticalOrder) {
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
// [searchResults removeAllObjects];
// [searchResults addObjectsFromArray:[inventoryProducts filteredArrayUsingPredicate:resultPredicate]];
searchResults=[inventoryProducts filteredArrayUsingPredicate:resultPredicate];
} else {
//-section mode
NSMutableArray *newDataArray=[NSMutableArray array];
for (NSMutableDictionary *aSectionDict in inventoryProducts) {
NSArray *sectionData=(NSArray*)[aSectionDict objectForKey:#"SECTION_DATA"];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
NSArray *filteredArray=[sectionData filteredArrayUsingPredicate:resultPredicate];
NSDictionary *sectionDataModified=[NSDictionary dictionaryWithObjectsAndKeys:filteredArray,#"SECTION_DATA",[aSectionDict objectForKey:#"SECTION_TITLE"],#"SECTION_TITLE", nil];
[newDataArray addObject:sectionDataModified];
}
searchResults=[NSArray arrayWithArray:newDataArray];
}
}
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
can anyone help?
Since you have added a search bar, you need to check if the cell is not nil:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// This is added for a Search Bar - otherwise it will crash due to
//'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell.
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
When you're using a UISearchDisplayController, the results are displayed in a separate UITableView that uses your original view controller as the delegate and data source. Since that UITableView isn't set up in your storyboard (it's dynamically created and loaded) it doesn't have access to your prototype cells. I was able to get a similar example to work by using:
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
I'm a little concerned about that since you're asking one tableview to create cells to use in a different table view.
It seems like the better approach will be to not create your cells as prototype cells, but instead create them in and load them from, a separate nib file.
You should also read the documents for UISearchDisplayController as there are several other details of the dataSource and delegate protocols that need to be updated to reflect the fact that there are multiple tableviews in play.
This is telling you that your method: cellForRowAtIndexPath is returning a cell that is nil. Which generates this error.
This line here: UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Will be nill, since you never assign anything to cell, nor do you do anything with it.
I created an RSS reader that parses from a .xml file. The numberOfRowsInSection and cellForRowAtIndexPath look like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.parseResults.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//Check if cell is nil. If it is create a new instance of it
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure titleLabel
cell.textLabel.text = [[self.parseResults objectAtIndex:indexPath.row] objectForKey:#"title"];
cell.textLabel.numberOfLines = 2;
//Configure detailTitleLabel
cell.detailTextLabel.text = [[self.parseResults objectAtIndex:indexPath.row] objectForKey:#"summary"];
cell.detailTextLabel.numberOfLines = 2;
//Set accessoryType
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
//Set font and style
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
return cell;
}
I am trying to create a search bar and search display controller, but am not sure how to search the objectForKey "title" or objectForKey "summary" within the UITableView.
Any help would be greatly appreciated.
If you are trying to search for both title and summary, can you try this in your UISearchBarDelegate method
- (void)searchBar:(UISearchBar *)searchBar
textDidChange:(NSString *)searchText
{
if ([searchText length] == 0)
{
[self.tableView reloadData];
return;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.title contains[cd] %# OR SELF.summary contains[cd] %#", searchText, searchText];
NSArray *filteredArray = [self.parseResults filteredArrayUsingPredicate:predicate];
// TODO: Use this filteredArray to reload data
[self.tableView reloadData];
}
Sample project for your reference - https://github.com/deepthit/TableViewSearch.git
I need to add a search bar for a table view.Table contain "Names" which is actually stored in inside an object called "patient".I have an array of "patient" objects.
So to setup a search bar to search for names.But how to do it using NSPredicate?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* CellId= #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellId];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellId] ;
}
cell.accessoryType = UITableViewCellAccessoryNone;
ObjPatient = [allPatientDetails objectAtIndex:indexPath.row];
cell.textLabel.text =[NSString stringWithFormat:#"%# %#",ObjPatient.firstName,ObjPatient.lastName];
return cell;
}
Above is the code to show the names on table.
Any suggestions are welcome , Thanks
To Implement search functionality first take look into below links -
https://developer.apple.com/library/ios/documentation/uikit/reference/UISearchBar_Class/Reference.html
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/Reference/NSPredicate.html
Then make changes in your code as follows -
In your .h file declare array -
NSArray *filteredArray;
In - (void)viewDidLoad method -
filteredArray = allPatientDetails;
Then implement UISearchBar delegate method-
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
NSPredicate *predicate = [NSPredicate
predicateWithFormat:#"SELF.firstName contains[c] %#",
searchText];
NSArray *filteredArray = [allPatientDetails filteredArrayUsingPredicate:predicate];
[tableView reloadData];
}
and make changes in your existing method -
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString* identifier= #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] ;
}
cell.accessoryType = UITableViewCellAccessoryNone;
ObjPatient = [filteredArray objectAtIndex:indexPath.row];
cell.textLabel.text =[NSString stringWithFormat:#"%# %#",ObjPatient.firstName,ObjPatient.lastName];
return cell;
}
well for nspredicate with custom object can be done like this.
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF.firstName contains[c] %#",
searchText];
self.searchedMemberNameResults = [self.listedMembers filteredArrayUsingPredicate:resultPredicate];
firstName is attribute of an object
Below you can find code for searching an item based on the label in the storyboard. It searches dynamically; I've tested this and it's working.
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"job_id contains[c] %#",searchText];
searchResultArray = [responceArray filteredArrayUsingPredicate:resultPredicate];
[jobsTable reloadData];
}
In my app I have 3 NSMutableArrays namely empJsonArray searchArray and nameArray
empJsonArray is populated using JSON.
nameArray is populated with valueForKey:#"Name" from empJsonArray and searchArray is initially populated with contents of empJsonArray.
the data is displayed in a UITableView
Now I am using UISearchBar for searching through my UITableView and display the relevant data. UISearchBar is working fine but the problem arises when the search data is displayed.
suppose I have 2 names that contain letter "T" when I search for "T" UITableView display 2 items but form the top of the nameArray (i.e. index 0 and 1) not the items that contain "T".
I am also using NSSortDescriptor.
Here's the code:-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MYCell"];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MYCell"];
}
sorter = [[NSSortDescriptor alloc]initWithKey:#"Name" ascending:YES selector:#selector(caseInsensitiveCompare:)];
sortedArray = [self.empJsonArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:sorter]];
cell.textLabel.text = [[sortedArray objectAtIndex:indexPath.row]objectForKey:#"Name"];
nameArray = [[NSMutableArray alloc]initWithArray:[sortedArray valueForKey:#"Name"]];
return cell;
}
Search Method:
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText {
if ([searchText length]==0) {
[searchArray removeAllObjects];
[searchArray addObjectsFromArray:nameArray];
}
else {
[searchArray removeAllObjects];
for (NSString *string in nameArray) {
NSRange r = [string rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (r.location != NSNotFound) {
[searchArray addObject:string];
}
}
}
[empTable reloadData];
}
you can see the screenshots here
1.Before search
2.After Search
Problem solved.
Instead of displaying the search result in cell
cell.textLabel.text = [[searchArray objectAtIndex:indexPath.row]
I was displaying
cell.textLabel.text = [[sortedArray objectAtIndex:indexPath.row]objectForKey:#"Name"];