views:

215

answers:

3

Hi,

Basically I'm trying to add a search function to my iPhone app, but I'm not having much luck at the moment. I've downloaded the Apple provided Table Search app, and have copied across the code to mine. It builds OK, but here's the problem. Unlike the Apple example, all my data is stored in an array, that is accessed by calling [ciParser.currentArray].

Any ideas on how to change the code to suit my needs? I'm getting an error "Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'" whenever I click on the search bar and the app exits. Below is the code in particular that the debugger highlights as being troublesome.

Apparently this error means the database trying to be searched is empty, but I could be wrong.

FYI my app downloads and parsers an RSS feed using a class which is referenced by ciParser - which in turn stores the downloaded content in an array that I need to search.

Update: It now seems my table isn't updating when it finds the information. Here's my code that should be doing that. Any ideas? Thanks.

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [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
{
    [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.

Code for parsing:

    // Customize the appearance of table view cells.
- (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] autorelease];
    }

    /*
     If the requesting table view is the search display controller's table view, configure the cell using the filtered content, otherwise use the main list.
     */
    CurrentItem * nextCurrentItem=[ciParser.currentArray objectAtIndex:indexPath.row];
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {


        // **(Code which debugger points to as being wrong)**
        nextCurrentItem = [self.filteredListContent objectAtIndex:indexPath.row];
    }
    else
    {
        nextCurrentItem = [ciParser.currentArray objectAtIndex:indexPath.row];
    }


    NSString*settingValue = [[NSUserDefaults standardUserDefaults]stringForKey:@"state"];
    if ([settingValue isEqualToString:@"New South Wales"]) {
    cell.textLabel.text=nextCurrentItem.title;
    }
    else if ([settingValue isEqualToString:@"Western Australia"]) {
        cell.textLabel.text=@"The FESA does not provide any Current Incident reports.";
    }
    else if ([settingValue isEqualToString:@"Victoria"]) {
        cell.textLabel.text=nextCurrentItem.title;
    }
    else if ([settingValue isEqualToString:@"South Australia"]) {
        cell.textLabel.text=nextCurrentItem.title;
    }
    else if ([settingValue isEqualToString:@"Tasmania"]) {
        cell.textLabel.text=nextCurrentItem.title;
    }
    // Set up the cell...

    [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];

    return cell;
}

Update: This is the section I don't think is right, as my search results now display blank, no matter what I type.

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    /*
     Update the filtered array based on the search text and scope.
     */

    [self.filteredListContent removeAllObjects]; // First clear the filtered array.

    /*
     Search the main list for products whose type matches the scope (if selected) and whose name matches searchText; add items that match to the filtered array.
     */

This part threw many errors and I eventually got it to this but I suspect this is my problem.

for (currentItem in ciParser.currentArray)
        {
            if ([scope isEqualToString:@"All"] || [currentItem.title isEqualToString:scope])
            {
                NSComparisonResult result = [currentItem.title compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
                if (result == NSOrderedSame)
                {
                    [self.filteredListContent addObject:currentItem];
                }
            }
        }
    }
A: 

Did you update the code for 'numberOfRowsInSection' to return the number of filtered items when searching? If not, this sounds like your problem.

Kevin Sylvestre
Thanks! It solved part of it, only now whenever I search for something it says no results found - even though its the same as one of the row titles. I've added the code for the search part which I don't think I did right above.
Graeme
Any ideas? I'm thinking the search array isn't being initialised with the information from the currentArray.
Graeme
A: 

You need to set breakpoints/logs in filterContentForSearchText:scope: to see where things are going wrong.

NSLog(@"searchText=%@",searchText);
NSLog(@"scope=%@",scope);
for (currentItem in ciParser.currentArray)
{
    NSLog(@"currentItem=%@",currentItem);
    if ([scope isEqualToString:@"All"] || [currentItem.title isEqualToString:scope])
    {
        NSLog(@"in ([scope isEqualToString:@"All"] || [currentItem.title isEqualToString:scope])");
        NSComparisonResult result = [currentItem.title compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
        NSLog(@"result=%d",result);
        if (result == NSOrderedSame)
        {
            NSLog(@"in (result == NSOrderedSame)");
            [self.filteredListContent addObject:currentItem];
            NSLog(@"self.filteredListContent=%@",self.filteredListContent);
        }
    }
}

This will give you a complete snap shot of the method in operation and tell you where the code is going wrong.

TechZen
OK have implemented this and it works (well in the console anyway). The console shows everything is working as normal, but my table still isn't showing the data (i.e. When I type the title of a cell, it shows as being found in the debugger, but table of search results still says not found). Any ideas?
Graeme
Do you call "reloadData" on the tableview so it will reload the cells?
TechZen
Where would you suggest this would go? I've checked and I have all the reloads in the same place as the TableSearch example.
Graeme
The most likely explanation is that the tableview controller isn't set as the searchDisplayController delegate so the `searchDisplayController:controller shouldReloadTableForSearchString:` etc methods are never being called.
TechZen
A: 

You need to implement:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString

And also:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption

I recommend you start by focusing either on the search string or the search options. Even try implementing a function that just copies over each item to your filtered array and check if it works.

Kevin Sylvestre
Hi, I did have those implemented - I've added them at the top of this post for your reference, because I have a suspicion I've done something wrong with it, given that the data is being searched its just not displaying when found.
Graeme