Question

I've based my code from this example. The initial data is shown in the table view but I'm not sure how to implement the rest to display the filtered data. I have no errors, search bar works but no filtered data. Here's my plist XML:

<dict>
    <key>Things to do</key>
    <array>
        <dict>
            <key>activity</key>
            <string>Watch movies or TV shows</string>
            <key>keywords</key>
            <array>
                <string>tv shows</string>
                <string>movies</string>
            </array>
        </dict>
        <dict>
            <key>activity</key>
            <string>Go Hiking</string>
            <key>keywords</key>
            <array>
                <string>hiking</string>
                <string>mountains</string>
            </array>
        </dict>
        <dict>
            <key>activity</key>
            <string>Video Games</string>
            <key>keywords</key>
            <array>
                <string>video games</string>
                <string>playstation</string>
                <string>xbox</string>
                <string>nintendo</string>
            </array>
        </dict>
    </array>
</dict>

Here is my CategoriesViewController.m:

@interface CategoriesViewController () <UISearchDisplayDelegate>

@property (nonatomic, strong) NSMutableArray *tableData;
@property (nonatomic, strong) NSMutableArray *searchResults;
@property (weak, nonatomic) IBOutlet UISearchBar *searchBar;

@end

- (void)viewDidLoad
{
[super viewDidLoad];
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"categories" ofType:@"plist"];
NSDictionary *categoriesDictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];

self.tableData = categoriesDictionary[@"Things to do"];
//I think this next line is supposed to make it appear on top of the original table
self.searchResults = [NSMutableArray arrayWithCapacity:[self.tableData count]];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {
        cell.textLabel.text = [self.searchResults objectAtIndex:indexPath.row];
    } else {
        cell.textLabel.text = self.tableData[indexPath.row][@"activity"];
    }

    return cell;
}

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{   
    [self.searchResults removeAllObjects];

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

    self.searchResults = [NSMutableArray arrayWithArray:[self.tableData filteredArrayUsingPredicate:resultPredicate]];
}

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

It's just like the example except I changed where my data is coming from. How can I search based on the keywords? In this example, am I only searching what is contained in my initial table view? Thanks for your time...

Was it helpful?

Solution

It's hard tell without more code, but I think you'll need to show/hide your two table views based on the search string.

If the string is empty, this will hid your searchResultsTableView and show your other table view which I'm I'm lovingly calling whatEverYouCalledYourOtherTableView.

If your string is not empty you do your search, show searchResultsTableView, hide whatEverYouCalledYourOtherTableView and reload the data for searchResultsTableView.

-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    if ([searchString isEqualToString:@""])
    {
        self.searchDisplayController.searchResultsTableView.hidden = YES;
        self.searchDisplayController.whatEverYouCalledYourOtherTableView.hidden = NO;
    }
    else
    {
        [self filterContentForSearchText:searchString
                                   scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
                           objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];


        self.searchDisplayController.searchResultsTableView.hidden = NO;
        self.searchDisplayController.whatEverYouCalledYourOtherTableView.hidden = YES;
        [self.searchDisplayController.searchResultsTableView reloadData];
    }
    return YES;
}

Also your filterContentForSearchText is wrong. You have an array of dictionaries not strings. First grab just the strings, then run your search. You'd be better off creating a dictionary of strings right away, the simplest way of getting your search to work is like this.

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{   
    [self.searchResults removeAllObjects];

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

    NSMutableArray *activityArray = [[NSMutableArray alloc] init];
    for (int i = 0; i < [self.tableData count]; i++)
    {
        [activityArray addObject:self.tableData[i][@"activity"]];
    }

    self.searchResults = [NSMutableArray arrayWithArray:[activityArray filteredArrayUsingPredicate:resultPredicate]];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top