0

i am trying to add search function in my app using NSpredicate. i have tried to get this to work and can't seem to see where the issue is. i recreated a demo app to show what i have done. everything shows up on simulator without any warnings, but when typing a text in search bar, there is no results. nothing shows in the search bar tableview. i am using search bar and search display controller object and also my original data source is a simple plist that contains dictionaries and each dictionary has 3 strings. everything works just fine except the search. can someone please take a look at my code and see where i went wrong ?

here is my .h file:

#import <UIKit/UIKit.h>

@interface TableViewController : UITableViewController <UISearchBarDelegate>

@property (strong, nonatomic) NSArray *content;
@property (strong, nonatomic) NSMutableArray *searchResults;

@end

and here is the .m file:

#import "TableViewController.h"
#import "DetailViewController.h"

@interface TableViewController ()

@end

@implementation TableViewController

@synthesize content = _content;
@synthesize searchResults = _searchResults;

-(NSArray *)content
{
if (!_content) {
    _content = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Data" ofType:@"plist"]];
}
return _content;
}

- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
    // Custom initialization
}
return self;
}

- (void)viewDidLoad
{
[super viewDidLoad];

_searchResults = [[NSMutableArray alloc] init];

}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

if (tableView == self.searchDisplayController.searchResultsTableView) {
    return [self.searchResults count];

} else {
    return [self.content count];

}
}

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{

[_searchResults removeAllObjects];

NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] '%@'",searchText];

[_searchResults addObjectsFromArray:[_content filteredArrayUsingPredicate:resultPredicate]];
}

-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
                           scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
                                  objectAtIndex:[self.searchDisplayController.searchBar
                                                 selectedScopeButtonIndex]]];

return YES;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

if (tableView == self.searchDisplayController.searchResultsTableView) {
    cell.textLabel.text = [_searchResults objectAtIndex:indexPath.row];
    cell.detailTextLabel.text = [_searchResults objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [[self.content objectAtIndex:indexPath.row] valueForKey:@"city"];
cell.detailTextLabel.text = [[self.content objectAtIndex:indexPath.row] valueForKey:@"state"];
}

return cell;
}



- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
    [self performSegueWithIdentifier: @"showDetails" sender: self];
}
}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

{

if ([segue.identifier isEqualToString:@"showDetails"]) {

    NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
    DetailViewController *DVC = [segue destinationViewController];

    if ([self.searchDisplayController isActive]) {

    DVC.cityImageString = [_searchResults objectAtIndex:indexPath.row];
    DVC.cityTextString = [_searchResults objectAtIndex:indexPath.row];
    } else {

        DVC.cityImageString = [[self.content objectAtIndex:indexPath.row] valueForKey:@"cityImage"];
        DVC.cityTextString = [[self.content objectAtIndex:indexPath.row] valueForKey:@"cityText"];
    }

}
}

@end

p.s. i am using xcode 4.6 ios 6 which i don't think would matter and may not be related to my question and also, I have added the searchbar through IB and its delegate and data source were connected automatically to the tableview.

thanks a bunch for helping in advance.

Edit:

here is the structure of my plist which is a very simple one, and i thought it might help someone offering me an answer.

     <?xml version="1.0" encoding="UTF-8"?>
     <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"   "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
       <plist version="1.0">
         <array>
      <dict>
    <key>city</key>
    <string>New York</string>
    <key>state</key>
    <string>NY</string>
    <key>cityText</key>
    <string>This is the description of the city that goes in the tex view just testing.</string>
    <key>cityImage</key>
    <string>acolon.png</string>
       </dict>
       <dict>
    <key>city</key>
    <string>Los Angeles</string>
    <key>state</key>
    <string>CA</string>
    <key>cityText</key>
    <string>This the second item&apos;s textview</string>
    <key>cityImage</key>
    <string>Piedirosso.jpg</string>
     </dict>
      <dict>
    <key>city</key>
    <string>Chicago</string>
    <key>state</key>
    <string>IL</string>
    <key>cityText</key>
    <string>here is the text view description for the third item.</string>
    <key>cityImage</key>
    <string>acolon.png</string>
</dict>
    </array>
    </plist>
Adrian P
  • 6,479
  • 4
  • 38
  • 55

2 Answers2

1

Nice work! but Checking the final code, I found if you select a cell from searchResults always shows the first cell, for example, for search "s" results: "Sandiago" and "Sprienfield", if""Sprienfield" is selected the detail view will be for Sandiago. I couldn't find the mistake.

  • you are correct. i forgot to update the project in git hub. basically this line was missing in the if statement in segue where the search is active: NSIndexPath *indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow]; happy you saw that one although that was never an issue in my project and was detected and fixed but thanks. – Adrian P May 29 '13 at 11:57
0

Your problem is the predicate on this line

NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] '%@'",searchText];

Your _content array contains NSDictionaries which don't support contains operator. Also, single/double quotes cause %@ to be used literally. (From docs: Single or double quoting variables (or substitution variable strings) cause %@, %K, or $variable to be interpreted as a literal in the format string and so prevent any substitution). Change this to:

NSPredicate *pred = [NSPredicate predicateWithFormat: @"SELF['city'] contains[cd] %@ OR SELF['state'] contains[cd] %@ OR SELF['cityText'] contains[cd] %@", searchText, searchText, searchText];

(assuming you want to search all three values: city, state, cityText)

maroux
  • 3,764
  • 3
  • 23
  • 32
  • the code you mentioned in your answer does not work. i have uploaded my project on github for the ease of access. will you please take the time to look at it. here is the link: https://github.com/AdrianPhillips/TableSearch – Adrian P Apr 26 '13 at 13:05
  • It's working fine on your code. I replaced [line 59](https://github.com/AdrianPhillips/TableSearch/blob/master/TableSearch/TableViewController.m#L59) to what I've written in my answer and after that searchResults is not empty. You can check that in the debugger. It does crash though - but that's because there are a lot of other problems with the code :) – maroux Apr 26 '13 at 13:15
  • well you were right, i had forgotten how to set up the cell. i must have been having too many drinks while writing this project.:) thank you for the fixes. i had to add to modify the code you gave me pretty much all the way to make it work the right way but i have to say that seeing the fixes you wrote opened my eys to see where i was and how to get where i want to be, so thank you for taking the time. i will check your answer as the correct one. thanks again – Adrian P Apr 26 '13 at 14:09
  • Glad I could help. I'm going to remove the code diff since it's not relevant to this question. – maroux Apr 26 '13 at 14:15
  • Sure thing . You were a great help. I will update the project on girhub and will post a link in my original answer so others can use it too. Great job man and keep up the good work. – Adrian P Apr 26 '13 at 14:18