Generate an error when trying to display the results in UITableView from user search

advertisements

Generating an error below when trying to display results in UITableView from search performed by the user. The code below is searching, filtering and should be displaying the results. (But isn't)

@implementation ProductsViewController

{
    NSPredicate *searchSearch;
    NSArray *results;
}

@synthesize bakeryTableView, bakeryProductArray, searchResults, itemName;

-(void)viewDidLoad
{
    bakeryProductArray = [[NSMutableArray alloc]init];
    searchResults = [[NSArray alloc]init];
    [self testermethod];
    [[self navigationController] setNavigationBarHidden:NO];
    [super viewDidLoad];
}

-(void)testermethod
{
    PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
    // Retrieve the top songs by sales
    [query orderByAscending:@"Name"];

    // Limit to retrieving ten songs
    query.limit = 100;
    [query findObjectsInBackgroundWithBlock:^(NSArray *food, NSError *error) {
        if (error) return;

        // Songs now contains the last ten songs, and the band field has
        // been populated. For example:
        for (PFObject *song in food) {

            PFObject *simple = [song objectForKey:@"Name"];

            [bakeryProductArray addObject: simple];
        }
        [bakeryTableView reloadData];
        return;
        NSLog(@"Passed");
    }];
}

-(id)initWithCoder:(NSCoder *)aCoder {
    self = [super initWithCoder:aCoder];
    if (self) {
        self.parseClassName = @"JackiesBakeryProducts";
        self.textKey = @"objectid";
        self.pullToRefreshEnabled = YES;
        self.paginationEnabled = NO;
       // self.objectsPerPage = 20;
    }

    return self;
}

-(PFQuery *)queryForTable
{
    PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];

    // If no objects are loaded in memory, we look to the cache first to fill the table
    // and then subsequently do a query against the network.
    if ([self.objects count] == 0) {
        query.cachePolicy = kPFCachePolicyCacheThenNetwork;
    }

    [query orderByAscending:@"Name"];

    return query;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    //Fill table in with data
    static NSString *cellIdentifier = @"Cell";
    PFObject *selectedObject = [self objectAtIndexPath:indexPath];
    NSLog(@"%@", selectedObject);
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
    }

    if (tableView == self.searchDisplayController.searchResultsTableView) {

            NSString *selectedObject = [searchResults objectAtIndex:indexPath.row];
            NSLog(@"%i", searchResults.count);
            cell.textLabel.text = selectedObject;
        }

    else {

        NSString *productName = [selectedObject objectForKey:@"Name"];
        NSString *productQuantity = [selectedObject objectForKey:@"Quantity"];

        cell.textLabel.text = productName;
        cell.detailTextLabel.text = productQuantity;
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    return cell;
}

#pragma mark - UITableView Delegate methods

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //Deal with user search from tableview
    if (bakeryTableView == self.searchDisplayController.searchResultsTableView)
    {

        [self performSegueWithIdentifier: @"bakeryDetails" sender:self];

    }

    //Prep the next view controller with data from current view (data passing)
    detailedViewController *productinfo = [self.storyboard instantiateViewControllerWithIdentifier:@"bakeryDetails"];

    PFObject *selectedObject = [self objectAtIndexPath:indexPath];

    productinfo.productName = [selectedObject objectForKey:@"Name"];
    productinfo.productImage = [selectedObject objectForKey:@"ImageUrl"];
    productinfo.productDescription = [selectedObject objectForKey:@"Description"];
    productinfo.productPrice = [selectedObject objectForKey:@"Price"];
    productinfo.productQuantity = [selectedObject objectForKey:@"Quantity"];
    productinfo.productAllergy = [selectedObject objectForKey:@"Allergy"];

    [self.navigationController pushViewController:productinfo animated:YES];
    [bakeryTableView deselectRowAtIndexPath:indexPath animated:YES];

}

//Becareful here as wrong predicateWithFormat can crash app on keying in search
-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope
{

    searchSearch = [NSPredicate predicateWithFormat:@"self CONTAINS[cd] %@",searchText];
    searchResults = [bakeryProductArray filteredArrayUsingPredicate:searchSearch];

    NSLog(@"Filtered Food Product Count --> %d",[searchResults count]);
    NSLog(@"%@", searchResults);
}

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

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Check to see whether the normal table or search results table is being displayed and return the count from the appropriate array
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {
        return [searchResults count];
    }
    else
    {
        return [bakeryProductArray count];
    }
}

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

@end

With the above code. It is generating an error with * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]' (It does work search with the 1st character typed in but crashes with the second)

I have rough idea that NSArray isn't working correctly when being called per index.row. But other than I don't know how to over come this.

Used @try - catch statement to report back what was happening in the searchResults. It produced this

2013-09-08 13:27:20.876 jackies[995:c07] Filtered Food Product Count --> 1
2013-09-08 13:27:20.876 jackies[995:c07] Aero
2013-09-08 13:27:20.877 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:20.877 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:20.877 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:20.877 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:20.877 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:20.877 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:20.878 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:20.878 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:32.550 jackies[995:c07] Filtered Food Product Count --> 1
2013-09-08 13:27:32.551 jackies[995:c07] Aero
2013-09-08 13:27:32.551 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:32.551 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:32.551 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:32.552 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:32.552 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:32.552 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:32.552 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:32.552 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:34.188 jackies[995:c07] Filtered Food Product Count --> 1
2013-09-08 13:27:34.189 jackies[995:c07] Aero
2013-09-08 13:27:34.189 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:34.189 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:34.189 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:34.189 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:34.189 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:34.190 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:34.190 jackies[995:c07] Caught this (
    Aero
)
2013-09-08 13:27:34.190 jackies[995:c07] Caught this (
    Aero
)

Any help would be great.


If you array contains dictionaries, the predicate is wrong. It would work if he bakeryProductArray where an array of strings, not dictionaries. Otherwise you would have to use

@"name CONTAINS[cd] %@"

as the format string.

Also make sure that you reload the table based on the search results array - i.e. check your datasource methods to return the correct number of rows.

A second point: it does not seem logical to retrieve the object you want to display before distinguishing between the two tables. The logic should be as follows:

UITableViewCell *cell = // dequeue cell
if (tableView == self.searchDisplayController.searchResultsTableView) {
  // retrieve object at IndexPath.row
  // configure the cell to display it
}
else {
  // do the same for main table view
}
return cell;