How should I use search controller instead of searchDisplayController in tableView method
I have an example code here
if (tableView == self.searchDisplayController.searchResultsTableView)
Hhere I am getting error on this line it says searchDisplayController is deprecated.
#implementation LocationsViewController
{
NSArray *_park;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.searchResult = [NSMutableArray arrayWithCapacity:[self->_park count]];
// Create a new JSONLoader with a local file URL
JSONLoader *jsonLoader = [[JSONLoader alloc] init];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"park" withExtension:#"json"];
// Load the data on a background queue...
// As we are using a local file it's not really necessary, but if we were connecting to an online URL then we'd need it
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_park = [jsonLoader locationsFromJSONFile:url];
// Now that we have the data, reload the table data on the main UI thread
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
});
}
//Just before showing the LocationDetailViewController, set the selected Location object
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
LocationDetailViewController *vc = segue.destinationViewController;
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
vc.location = [_park objectAtIndex:indexPath.row];
}
#pragma mark - Table View Controller Methods
//UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"LocationCell"];
Location *location = [_park objectAtIndex:indexPath.row];
cell.textLabel.text = location.name;
cell.detailTextLabel.text = location.address;
// cell.detailTextLabel.text = location.ide;
cell.imageView.image = [UIImage imageNamed:#"location_image"];
///////////////////
if (tableView == self.searchDisplayController.searchResultsTableView)
{
cell.textLabel.text = [self.searchResult objectAtIndex:indexPath.row];
}
else
{
cell.textLabel.text = self->_park[indexPath.row];
}
/////////////////
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//////////////////////////////////////////////
if (tableView == self.searchDisplayController.searchResultsTableView)
{
return [self.searchResult count];
}
else
{
return [self->_park count];
}
//////////////////////////////////////////////
return [_park count];
}
/////////////////////////////////////////////////
- (void)filterContentForSearchText:(NSString*)searchText scope: (NSString*)scope
{
[self.searchResult removeAllObjects];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#", searchText];
self.searchResult = [NSMutableArray arrayWithArray: [self->_park filteredArrayUsingPredicate:resultPredicate]];
}
-(BOOL)searchDisplayController:(UISearchController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString scope: [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
#end
I believe you have declared a UISearchController by passing nil as a parameter to searchResultsController. So your same tableView is being used as searchResultsController of UISearchController
like
let searchController = UISearchController(searchResultsController: nil)
or
UISearchController searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
I hope all you want to do now is to distinguish whether UISeacrhController is active or it's your tableView so that you can show different cell for them :)
If so,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"LocationCell"];
Location *location = [_park objectAtIndex:indexPath.row];
cell.textLabel.text = location.name;
cell.detailTextLabel.text = location.address;
// cell.detailTextLabel.text = location.ide;
// cell.imageView.image = [UIImage imageNamed:#"location_image"];
if (searchController.active)
{
cell.textLabel.text = [self.searchResult objectAtIndex:indexPath.row];
}
else
{
cell.textLabel.text = self->_park[indexPath.row];
}
/////////////////
return cell;
}
My answer in comment if (tableView == self.yourSearchController. searchResultsController) would have worked if you had instantiated a different tableView controller and provided as SearchResultsController for UISearchController
But because you have specified nil in your init of UISearchControllersame tableView instance will be used as SearchResultsController. So comparing will result in always yes :)
Rather, you can depend on active property of UISearchController and check in what context tableView is being used and handle it appropriately :)
Hope I made my point clear :) Happy coding :)
Related
I make dictionary in iOS, I get data from JSON url. I have problem with correctly display result of word from SearchBar. For example when I type something in searchBar and click on some result , always display value of first result.
Below I put my screen to present this problem.
On the second screen I click on Ruby on Rails and show me first of result "Objective C", why (Objective C is a first result in JSON file)?
And it's my code: http://pastebin.com/EPVTpF9U
#pragma mark - Navigation
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"pushDetailView"]){
NSIndexPath * indexPath = [self.tableView indexPathForSelectedRow];
DetailViewController *modalVC = (DetailViewController*)segue.destinationViewController;
modalVC.detailArray = [self.finalResultArray objectAtIndex:indexPath.row];
}
}
#pragma mark - UISearchDisplayDelegate
// register a cell reuse identifier for the search results table view
-(void)searchDisplayController:(UISearchDisplayController *)controller
didLoadSearchResultsTableView:(UITableView *)tableView {
[tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:#"Cell"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(tableView == self.tableView){
return self.finalResultArray.count;
}else{
return self.results.count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdetifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdetifier forIndexPath:indexPath];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdetifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if(tableView == self.tableView){
cell.textLabel.text = [[self.finalResultArray objectAtIndex:indexPath.row] objectForKey:#"expression"];
cell.detailTextLabel.text = [[self.finalResultArray objectAtIndex:indexPath.row] objectForKey:#"meaning"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
else{
cell.textLabel.text = [[self.results objectAtIndex:indexPath.row] objectForKey:#"expression"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
UIView *customColorView = [[UIView alloc] init];
customColorView.backgroundColor = [UIColor colorWithRed:180/255.0
green:138/255.0
blue:171/255.0
alpha:0.5];
cell.selectedBackgroundView = customColorView;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"pushDetailView" sender:self];
}
- (void)simpleJsonParsing
{
//-- Make URL request with server
NSHTTPURLResponse *response = nil;
NSString *jsonUrlString = [NSString stringWithFormat:#"https://uidictionary.herokuapp.com/phrases.json"];
NSURL *url = [NSURL URLWithString:[jsonUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
//-- Get request and response though URL
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//-- JSON Parsing
NSArray *result = [[NSJSONSerialization JSONObjectWithData:responseData options:
NSJSONReadingMutableContainers error:nil] objectForKey:#"phrases"];
[self.finalResultArray removeAllObjects];
for (NSMutableDictionary *tmp in result)
{
NSMutableDictionary *temp = [NSMutableDictionary new];
[temp setObject:[tmp objectForKey:#"expression"] forKey:#"expression"];
[temp setObject:[tmp objectForKey:#"meaning"] forKey:#"meaning"];
[self.finalResultArray addObject:temp];
}
if (self.finalResultArray){
[self.tableView reloadData];
}
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
self.results = [self.finalResultArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%K contains[c] %#", #"expression", searchController.searchBar.text]];
NSLog(#"Filterd Array:-%#", self.results);
// hand over the filtered results to our search results table
UITableViewController *tableController = (UITableViewController *)self.searchController.searchResultsController;
tableController.tableView.dataSource = self;
tableController.tableView.delegate = self;
[tableController.tableView reloadData];
}
Just replace Bellow Code :-
self.results = [self.finalResultArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%K BEGINSWITH[c] %#", #"expression", searchController.searchBar.text]];
#mechu911
Replace your method with below code.
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"pushDetailView"]){
NSIndexPath * indexPath = [self.tableView indexPathForSelectedRow];
DetailViewController *modalVC = (DetailViewController*)segue.destinationViewController;
modalVC.detailArray = [self.result objectAtIndex:indexPath.row];
}
}
but you have to put check like
if(tableView == self.tableView){
modalVC.detailArray = [self.finalResultArray objectAtIndex:indexPath.row];}
else{modalVC.detailArray = [self.result objectAtIndex:indexPath.row];}
I made a list in tableviewcontroller, then add search bar and search display. But due to the fact that I have an array in Russian language search is not working. If I add the numbers in the array and start search it's work. But if on the Russian letters, no. How to fix it?
My code
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
_items
= [NSArray arrayWithObjects:
#"А",
#"Ак",
#"Ба",
#"Бо",
#"22",
#"23",
nil];
}
return self;
}
#pragma mark - UISearchDisplayDelegate
// register a cell reuse identifier for the search results table view
-(void)searchDisplayController:(UISearchDisplayController *)controller
didLoadSearchResultsTableView:(UITableView *)tableView {
[tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:#"SearchResultsTableViewUITableViewCell"];
}
// perform the search
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchString:(NSString *)searchString {
NSPredicate *predicate
= [NSPredicate predicateWithFormat:#"self beginswith %#", searchString];
NSArray *searchResults
= [[self items] filteredArrayUsingPredicate:predicate];
[self setSearchResults:searchResults];
return YES;
}
#pragma mark - UITableViewDataSource
// check if displaying search results
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
if ([[self searchDisplayController] isActive]) {
return [[self searchResults] count];
} else {
return [[self items] count];
}
}
// check if displaying search results
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([[self searchDisplayController] isActive]) {
UITableViewCell *cell
= [tableView dequeueReusableCellWithIdentifier:#"SearchResultsTableViewUITableViewCell"
forIndexPath:indexPath];
id item = [[self searchResults] objectAtIndex:[indexPath row]];
[[cell textLabel] setText:item];
return cell;
} else {
UITableViewCell *cell
= [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"
forIndexPath:indexPath];
id item = [[self items] objectAtIndex:[indexPath row]];
[[cell textLabel] setText:item];
return cell;
}
}
#pragma mark - UITableViewDelegate
// manually perform detail segue after selecting a search result
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if ([[self searchDisplayController] isActive]) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:#"detailSegue" sender:cell];
}
}
#pragma mark - UIViewController
/* prepare for detail scene segue
called after cell selection in the master and
search results table views */
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UITableViewCell *cell = (UITableViewCell *)sender;
id item = nil;
if ([[self searchDisplayController] isActive]) {
NSIndexPath *indexPath
= [[[self searchDisplayController] searchResultsTableView] indexPathForCell:cell];
item = [[self searchResults] objectAtIndex:[indexPath row]];
} else {
NSIndexPath *indexPath
= [[self tableView] indexPathForCell:cell];
item = [[self items] objectAtIndex:[indexPath row]];
}
UIViewController *detail
= (UIViewController *)[segue destinationViewController];
[[detail navigationItem] setTitle:item];
}
#end
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains [cd] %#", self.searchBar.text];
self.searchResults = [[_actualItems filteredArrayUsingPredicate:predicate] mutableCopy];
I'm trying to implement a UISearchBar in a custom UITableViewController and done programmatically (not using IB). I got the search function to work and return the correct fields, but it is displaying the searched cells over the full list cells:
As you can see, the new searched field is scrollable and selectable. Its just not removing the old cells.
here is my .h file:
#interface TestTableViewController : UITableViewController <UISearchBarDelegate, UISearchDisplayDelegate>
#property (strong, nonatomic) NSArray *boundaries;
#end
.m file:
#import "TestTableViewController.h"
#import "Boundary.h"
#interface TestTableViewController ()
#property (strong, nonatomic) UISearchDisplayController *searchController;
#property (strong, nonatomic) NSMutableArray *filteredBoundaries;
#end
#implementation TestTableViewController
-(instancetype) initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
self.filteredBoundaries = [NSMutableArray array];
}
return self;
}
-(void)viewDidLoad {
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:TRUE selector:#selector(caseInsensitiveCompare:)];
NSArray *sortDescriptors = #[sortDescriptor];
self.boundaries = [self.boundaries sortedArrayUsingDescriptors:sortDescriptors];
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
searchBar.delegate = self;
searchBar.placeholder = #"Search Fields";
searchBar.showsCancelButton = TRUE;
self.tableView.tableHeaderView = searchBar;
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
}
// ------------------------------------------------------------------------------------------------------
#pragma mark -
#pragma mark Setup Filter Data Source
-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope {
[self.filteredBoundaries removeAllObjects];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
self.filteredBoundaries = [NSMutableArray arrayWithArray:[self.boundaries filteredArrayUsingPredicate:predicate]];
}
// ------------------------------------------------------------------------------------------------------
#pragma mark -
#pragma mark Table view data source
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.searchDisplayController.searchResultsTableView) {
return self.filteredBoundaries.count;
}
else {
return self.boundaries.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];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
Boundary *boundary = [self.filteredBoundaries objectAtIndex:indexPath.row];
cell.textLabel.text = boundary.name;
cell.textLabel.textColor = [UIColor blackColor];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
}
else {
Boundary *boundary = [self.boundaries objectAtIndex:indexPath.row];
cell.textLabel.text = boundary.name;
cell.textLabel.textColor = [UIColor blackColor];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.userInteractionEnabled = TRUE;
}
return cell;
}
// ------------------------------------------------------------------------------------------------------
#pragma mark -
#pragma mark UISearchDisplayController Delegates
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterContentForSearchText:searchString scope:[[self.searchController.searchBar scopeButtonTitles] objectAtIndex:self.searchController.searchBar.selectedScopeButtonIndex]];
return TRUE;
}
#end
And how I call the table view:
TestTableViewController *tableViewController = [[TestTableViewController alloc] initWithStyle:UITableViewStylePlain];
tableViewController.boundaries = [group.boundaries allObjects];
tableViewController.contentSizeForViewInPopover = POPOVER_SIZE;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tableViewController];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
navController.navigationBar.barStyle = UIBarStyleBlack;
self.myPopoverController = [[UIPopoverController alloc] initWithContentViewController:navController];
self.myPopoverController.delegate = self;
[self.myPopoverController presentPopoverFromRect:button.frame inView:button.superview permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Any ideas what I might be doing wrong or missing?
The problem is that UISearchDisplayController is using another UITableView rather than the view controller's own. You can verify that by logging tableView in -tableView:cellForRowAtIndexPath:.
You can use a UISearchBar without a UISearchDisplayController, to have more control over search and display logic.
Also, if your app doesn't support any version prior to iOS 8, consider using UISearchController. I haven't tried it but it seems to give you more control. Check a sample UISearchDisplayControllerhas been deprecated in iOS 8.
Try this
searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 41.0)];
[self.view addSubview:searchBar];
searchBar.delegate=self;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
if (isSearching) {
return [filteredContentList count];
}
else {
return [titlearray count];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (isSearching)
{
cell.nameLabel.text = [filteredContentList objectAtIndex:indexPath.row];
cell.thumbnailImageView.image =[filteredImgArray objectAtIndex:indexPath.row];
}
else
{
cell.thumbnailImageView.image = [imagearray objectAtIndex:indexPath.row];
cell.nameLabel.text = [titlearray objectAtIndex:indexPath.row];
}
return cell;
}
- (void)searchTableList {
NSString *searchString = searchBar.text;
for (int i=0; i<titlearray.count; i++) {
NSString *tempStr=[titlearray objectAtIndex:i];
NSComparisonResult result = [tempStr compare:searchString options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchString length])];
if (result == NSOrderedSame)
{
[filteredContentList addObject:tempStr];
[filteredImgArray addObject:[imagearray objectAtIndex:i]];
}
}
}
#pragma mark - Search Implementation
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
isSearching = YES;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(#"Text change - %d",isSearching);
//Remove all objects first.
[filteredContentList removeAllObjects];
[filteredImgArray removeAllObjects];
if([searchText length] != 0) {
isSearching = YES;
[self searchTableList];
//tblContentList.hidden=NO;
}
else {
isSearching = NO;
// tblContentList.hidden=YES;
}
[tblContentList reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Cancel clicked");
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSLog(#"Search Clicked");
[self searchTableList];
}
I hope it's help for you
You should implement correct datasource.
Create new array of items for filtered data for first.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger count = ([filteredItems count] > 0) ? [filteredItems count] : [self.allItems count];
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier: #"id"];
MyCustomItem *item = ([filteredItems count] > 0) ? filteredItems[indexPath.row] : self.allItems[indexPath.row];
[self configureCell:cell forItem:item];
return cell;
}
Configure searching:
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
NSString *searchText = searchController.searchBar.text;
if ([searchText length] == 0)
{
[filteredItems removeAllObjects];
[self.tableView reloadData];
return;
}
NSMutableArray *searchResults = [self.allItems mutableCopy];
// SKIP ALL BODY OF SEARCHING
filteredPeoples = searchResults;
[self.tableView reloadData];
}
Will work pretty.
IOS 8 delegate has been deprecated not sure if that's the problem.
The method
here's [a link]https://developer.apple.com/Library/ios/documentation/UIKit/Reference/UISearchDisplayDelegate_Protocol/index.html#//apple_ref/occ/intfm/UISearchDisplayDelegate/searchDisplayControS 8 delegate has been deprecated not sure if that's the problem.
The method
try this property instead
#property(nonatomic, assign) id< UISearchResultsUpdating > searchResultsUpdater
another better link [a link]https://developer.apple.com/library/ios/samplecode/TableSearch_UISearchController/Listings/TableSearch_obj_c_TableSearch_APLResultsTableController_m.html
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.
I am fairly new to Xcode so I have been using a tutorial on how to implement a SearchBar in my notes app. The SearchBar retrieves the data from the table view but when I click on it it doesn't take me to the page. How would I fix this problem in UIStoryboardSegue keeping in mind I'm new to all this stuff! Thanks in advance:3
#import "DeviceViewController.h"
#import "DeviceDetailViewController.h"
#interface DeviceViewController ()
#property (strong) NSMutableArray *devices;
#end
#implementation DeviceViewController
{
NSArray *searchResults;
}
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
//label.backgroundColor = [UIColor clearColor];
label.font = [UIFont fontWithName:#"HelveticaNeue-thin" size:28];
//label.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.5];
label.textColor = [UIColor blackColor];
self.navigationItem.titleView = label;
label.text = #"TapNotes";
[label sizeToFit];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Device"];
self.devices = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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.devices.count;
}
//return self.devices.count;
}
- (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]; }
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [device valueForKey:#"name"]]];
[cell.detailTextLabel setText:[NSString stringWithFormat:#"%#",[device valueForKey:#"version"]]];
if (tableView == self.searchDisplayController.searchResultsTableView) {
device = [searchResults objectAtIndex:indexPath.row];
} else {
[self.devices objectAtIndex:indexPath.row];
}
// cell.thumbnailImageView.image = [UIImage imageNamed:recipe.image];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.devices objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.devices removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
/*
// 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
[tableView deleteRowsAtIndexPaths:#[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
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"UpdateDevice"]) {
NSManagedObject *selectedDevice = [self.devices objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
NSIndexPath *indexPath = nil;
//Device *device = nil;
if (self.searchDisplayController.active) {
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
_devices = [searchResults objectAtIndex:indexPath.row];
} else {
indexPath = [self.tableView indexPathForSelectedRow];
_devices = [_devices objectAtIndex:indexPath.row];
}
DeviceDetailViewController *destViewController = segue.destinationViewController;
destViewController.device = selectedDevice;
}
}
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
searchResults = [_devices 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
A UIStoryboardSegue can only be connected via a storyboard. Since you are presenting your search data through the UISearchDisplayController, you need to implement tableView:didSelectRowAtIndexPath:. In this method you need to make sure you are only performing a push to a new view controller when you are receiving events from the tableview connected to UISearchDisplayController In this method I would recommend you to use performSegueWithIdentifier: and manually connect a segue in you storyboard. See this answer for more details on how to create a manual segue: https://stackoverflow.com/a/17012857/1049509