0

I sometimes get an NSRangeException when I am populating my search array data from the web service. In my example, I reload the search display controller table every time I key in data from the search box. The search entry is then sent to foursquare search api, and once the data is retrieved, I update the my search array data model.

This is how it works:

 - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self searchVenuesFromFoursquare:searchString];
    return YES;
}

In the above method, the delegate is called everytime the user enters a value in the search box. It then reloads the search table. In the meantime, my web service call to Foursquare is trying to retrieve the venues matching the search term.

- (void)searchVenuesFromFoursquare:(NSString *)searchTerm
{
  void(^completionBlock)(NSArray *obj, NSError *err) =
    ^(NSArray *obj, NSError *err)
    {
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        self.searchVenues = obj;
        [self.searchDisplayController.searchResultsTableView reloadData];
    });
};

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
if (self.deviceLocation) {
    NSString *latLon = [NSString stringWithFormat:@"%g,%g", self.deviceLocation.coordinate.latitude, self.deviceLocation.coordinate.longitude];
    [[MakanKakiStore sharedStore]searchVenues:completionBlock withSearchTerm:searchTerm andDeviceLatLng:latLon];
}
else{
    [[MakanKakiStore sharedStore]searchVenues:completionBlock withSearchTerm:searchTerm andDeviceLatLng:nil];
  }
}

The problems seems to occur in this portion.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableView == self.searchDisplayController.searchResultsTableView) {
    VenueSearchTableViewCell *searchVenueCell = [tableView dequeueReusableCellWithIdentifier:@"VenueSearchTableViewCell" forIndexPath:indexPath];
    [searchVenueCell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];

        NSDictionary *venueDict = [self.searchVenues objectAtIndex:indexPath.row];
        searchVenueCell.venueName.text = venueDict[@"name"];
        return searchVenueCell;
   }
}

When the cellForRow is trying to retrieve the venueDict from the searchVenues array, I think the Range Exception can occur when the model suddenly changes due to the web service call. This problem is very hard to duplicate as it depends on the web service response speed and the user input.

My temporary fix for now is to add this check

if (indexPath.row + 1 <= self.searchVenues.count) {
    NSDictionary *venueDict = [self.searchVenues objectAtIndex:indexPath.row];
}

This seems to be the best solution for now and prevents the range exception problem. However, I was wondering if there is a best practice towards tackling this problem? Most tutorials on UISearchDisplayController seems to be tackling data that is initialize locally rather than from a remote web server.

Hence, I would really appreciate if someone could advice me if there is a best practices approach when populating data for UISearchDisplayController.

Thank you so much.

Qin Zhengquan
  • 467
  • 1
  • 8
  • 20

1 Answers1

-1

Have a look at this answer and it will most likely solve all your problems. You will basically throttle your requests to the Foursquare web service. Code:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    static NSTimer *timer;
    [timer invalidate];
    timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(searchVenuesFromFoursquare:) userInfo:@{@"searchString": searchString} repeats:NO];
    return NO;
}

- (void)searchVenuesFromFoursquare:(NSTimer *)timer
{
    NSString *searchString = timer.userInfo[@"searchString"];
    ...
}

Requests to a web service or data store should take place as infrequently as possible while achieving the desired goal.

Community
  • 1
  • 1
duci9y
  • 4,128
  • 3
  • 26
  • 42