Unnecessary empty space below search results using UISearch - ios

I have tab in my app, where user can perform search. After user type keywords and tableView populated with results, there a lot of empty rows. I already "clean" unnecessary rows (turned it to [UIColor clearColor]), but now i got an empty space, problem wasn't solved. What i want is, just a table populated with search results, no empty space, no rows (it perfectly fine if there is blank space, when there is only several results on a table. But i got this "empty" space when there is many results, and i have to scroll down to see all of them. In that case, i didn't want that anything appears after last cell). There is a code, i use to create UISearch and tableView, it pretty straightforward:
For UITableView:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSLog(#"number of rows is ? %d", self.filteredArray.count);
return [self.filteredArray 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];
}
NSString *_cellText = self.filteredArray[indexPath.row];
cell.textLabel.text = _cellText;
return cell;
}
For UISearch:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
self.filteredArray = [NSMutableArray new];
self.searchResults = [NSArray new];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
self.searchResults = [self._placeOfObjects filteredArrayUsingPredicate:resultPredicate];
NSLog(#" metod called ");
NSLog(#"searchResults is %#", self.searchResults);
// if (self.searchResults){
// _filteredName = ((placeHolder *)(self.searchResults)).name;
// NSLog(#"HOLY Grale %#", _filteredName);
// }
// NSLog(#" What user search is %#", ((placeHolder *)(self.searchResults.name));
if (self.searchResults.count > 0){
// _filteredName = ((placeHolder *)(self.searchResults[0])).name;
for (int i=0; i<[self.searchResults count]; i++) {
NSLog(#" counto %d", [self.searchResults count]);
_filteredName = ((PlaceHolder *)(self.searchResults[i])).name;
[self.filteredArray addObject:_filteredName];
}
}
else {
NSLog(#"array is empty");
}
NSLog(#"HOLY WATER %#", _filteredName );
NSLog(#" %# holy array", self.filteredArray);
}
-(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;
}
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView;
{
UIView *footer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 1)];
footer.backgroundColor = [UIColor clearColor];
[tableView setTableFooterView:footer];
}
Any advice would be appreciated, thanks!

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.

Updating UITableView while UISearchBar is active

I am writing an iOS chat application wherein I have to show the users list with a search bar. I am getting the updated user list from the server after every 2 min.
The problem that I am facing is
Case:1
If I have the search bar active and I call reload table when the datasource is updated, now if I cancel the search, I do not get my original table. Only the filtered results are shown.
Case: 2
If I have the search bar active and I just update the data source and do not reload the table, now if I cancel the search, it loops to cellforrowatindexpath as many times as there are elements in the new datasource but it does not show the updated elements. Infact, it jumbles up the elements because it considers the new index paths but uses the old data.
By jumbled up I mean,
Say if the old datasource is a1, a2, a3 and a4 with avatar images a1, a2, a3, a4.
The new datasource is a5, a1, a2, a3, a4 with images a5, a1, a2, a3, a4.
So the jumbled view that I get is
a1 with a5 image,
a2 with a1 image,
a3 with a4 image
a4 with no image.
4 cells instead of 5.
Case: 3 (working correctly)
If I have the search bar active and I do not even update the data source, nothing happens when I cancel the search (as expected). I have to reload the table to get the updated view.
What I want is that it should update the table even if search is active and when I cancel the search I should get the updated table view. I know this can be achieved by reload table when cancel button is clicked but I am trying to find an elegant solution to this.
Also, please tell me the concept (the inner workings) behind why is this working like this.
My code:
- (void)refreshUserList
{
if(dtclass.updatedUserList && [resultsArray count] ==0)
{
userArray = dtclass.getUpdatedUserList;
[self.tableView reloadData];
[dtclass setUpdatedUserList:NO];
}
else if(dtclass.updatedUserList && [resultsArray count] !=0)
{
//Uncomment for Case:1
/*userArray = dtclass.getUpdatedUserList;
[dtclass setUpdatedUserList:NO];
[self.tableView reloadData];*/
//Uncomment for Case:2
/*userArray = dtclass.getUpdatedUserList;
[dtclass setUpdatedUserList:NO];*/
//remove else if code for Case:3
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
if (resultsArray.count != 0)
{
return [resultsArray count];
}
return userArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView setSeparatorInset:UIEdgeInsetsMake(0, 70, 0, 0)];
GlobalListTableViewCell *cell = (GlobalListTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"GlobalListCell"];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"GlobalListTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
//custome class User
User *currentUser;
if(resultsArray.count !=0)
{
currentUser = [resultsArray objectAtIndex:indexPath.row];
}
else
{
currentUser = [userArray objectAtIndex:indexPath.row];
}
cell.nameLabel.text = currentUser.getName;
cell.timeLabel.text = #"5 pm";
dispatch_async(fetchImage, ^{
if([[currentUser getAvatarUrl] length]!=0)
{
[self loadImagesWithURL:[NSString stringWithFormat:#"%#%#",#"http:",[currentUser getAvatarUrl]] IndexPath:indexPath];
}
});
cell.avatarImage.image = [UIImage imageNamed:#"defaultUser.png"];
cell.messageLabel.text = #"No message";
return cell;
}
-(void) loadImagesWithURL:(NSString *)imageURL IndexPath:(NSIndexPath *)indexPath
{
NSURL *url = [NSURL URLWithString:imageURL];
NSData *data = [[NSData alloc ] initWithContentsOfURL:url];
UIImage *img = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
GlobalListTableViewCell *cell = (GlobalListTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
cell.avatarImage.image = img;
});
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath
{
return 60;
}
- (void)filterContentForSearchText:(NSString*)searchText scope: (NSString*)scope
{
resultsArray = [[NSArray alloc] init];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF.getName contains[c] %#", searchText];
resultsArray = [userArray filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope: [[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex: [self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *) aSearchBar {
aSearchBar.text = nil;
}
Try this code for search ..
- (void)filterContentForSearchText:(NSString*)searchText
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.getName contains[c] %#",searchText];
_filteredGarages = [NSMutableArray arrayWithArray:[_allGarages filteredArrayUsingPredicate:predicate]];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[_filteredGarages removeAllObjects];
if([searchText length] != 0) {
[self filterContentForSearchText:searchText];
}
[self.tableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
isSearching = NO;
[self.tableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
if([searchBar.text isEqualToString:#""])
isSearching = NO;
else isSearching = YES;
[self.tableView reloadData];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
if([searchBar.text isEqualToString:#""])
isSearching = NO;
else isSearching = YES;
[self.tableView reloadData];
}
- (void)viewDidLoad {
[super viewDidLoad];
resultsArray = [[NSMutableArray alloc] init];
isSearching = NO;
userArray = [[NSMutableArray alloc] init];
userArray = [//GetYourData//];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [resultsArray count];
} else {
return [userArray count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Do you table view cell job here ...
if (tableView == self.searchDisplayController.searchResultsTableView) {
isSearching = YES;
//fill the cell using resultsArray
} else {
//fill the cell using userArray
}
}

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.

Repopulating UITableView after search

I'm using single NSFetchedResultController to populate both self.tableView and UISearchDisplayControler.tableView. After using search bar and dismissing it if I select any row in the self.tableView I get this error:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
I guess that somewhere I miss reloading data but I have no clue where?
Here are some methods which I use for populating both tabble views:
#pragma mark - Table View
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Count sections in FRC
return [[self.groupsFRC sections] count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Count groups in each section of FRC
return [[[self.groupsFRC sections] objectAtIndex:section] numberOfObjects];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Get reusable cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"GroupCell"];
// If there isn't any create new one
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"GroupCell"];
}
Group *group = [self.groupsFRC objectAtIndexPath:indexPath];
cell.textLabel.text = group.name;
// Checking if group has been selected earlier
if ([self.selectedGroups containsObject:#{#"name" : group.name, #"id" : group.cashID}]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
return cell;
}
// Adding checkmark to selected cell
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
Group *group = [self.groupsFRC objectAtIndexPath:indexPath];
// Checking if selected cell has accessory view set to checkmark and add group to selected groups array
if (selectedCell.accessoryType == UITableViewCellAccessoryNone)
{
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedGroups addObject:#{#"name" : group.name, #"id" : group.cashID}];
NSLog(#"%#", self.selectedGroups);
}
else if (selectedCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
selectedCell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedGroups removeObject:#{#"name" : group.name, #"id" : group.cashID}];
NSLog(#"%#", self.selectedGroups);
}
// Hiding selection with animation for nice and clean effect
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - Filtering
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF.name contains[c] %#", searchText];
self.groupsFRC = [Group MR_fetchAllSortedBy:#"caseInsensitiveName"
ascending:YES
withPredicate:resultPredicate
groupBy:#"sectionLetter"
delegate:self];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
-(void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
// Setting FRC to fetch original table view data
self.groupsFRC = [Group MR_fetchAllSortedBy:#"caseInsensitiveName"
ascending:YES
withPredicate:nil
groupBy:#"sectionLetter"
delegate:self];
}
Okey, I finally get over this problem but with skipping UISearchDisplayDelegate and implementing this only using UISearchBarDelegate. Here is the code:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchText.length > 0) {
resultPredicate = [NSPredicate predicateWithFormat:#"SELF.name contains[c] %#", searchText];
} else {
resultPredicate = nil;
}
[self refreshFRC];
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
resultPredicate = nil;
[self refreshFRC];
}
- (void)refreshFRC {
if (resultPredicate != nil) {
self.groupsFRC = [Group MR_fetchAllSortedBy:#"caseInsensitiveName"
ascending:YES
withPredicate:resultPredicate
groupBy:#"sectionLetter"
delegate:self];
} else {
self.groupsFRC = [Group MR_fetchAllSortedBy:#"caseInsensitiveName"
ascending:YES
withPredicate:nil
groupBy:#"sectionLetter"
delegate:self];
[self.tableView reloadData];
}
}

UISearchBar error - NSRangeException

I'm getting an error trying to use a UISearchBar to filter objects from an array that populate a UITableView. The error states: Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 3 beyond bounds [0 .. 2]'.
The relevant code in ViewController.m is:
- (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];
}
if (isFiltered == YES)
{
NSLog (#"%i", indexPath.row);
cell.textLabel.text = [filteredCities objectAtIndex:indexPath.row];
}
else
{
cell.textLabel.text = [initialCities objectAtIndex:indexPath.row];
}
return cell;
}
#pragma mark - UISearchBar Delegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if (searchText.length == 0)
{
isFiltered = NO;
}
else
{
isFiltered = YES;
filteredCities = [[NSMutableArray alloc] init];
for (NSString *cityName in initialCities)
{
NSRange cityNameRange = [cityName rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (cityNameRange.location != NSNotFound)
{
[filteredCities addObject:cityName];
}
}
}
[myTableView reloadData];
}
#end
You should also change tableView:numberOfRowsInSection method to something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (isFiltered) {
return [filteredCities count]; /// Filtered items
}
return [initialCities count]; /// All items
}
there is a better way to do this. you should use a search bar controller. and use these two delegate methods.
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF.property contains[cd] %#",
searchText];
self.searchResults = [self.datasource filteredArrayUsingPredicate:resultPredicate];
}
// code to refresh the table with the users search criteria
// this gets called everytime the user search string changes.
// also it calls the function above.
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
Now in your table view. you can refer to the new table the search bar controller creates by saying
self.searchBarController.searchResultsTable
and you can put this in the if else and check to see the table rather than using an isFiltered property.
if (tableView == self.searchDisplayController.searchResultsTableView){
} else { // your in the other original table

Resources