Search code examples
iosobjective-cuitableviewuisearchbaruisearchdisplaycontroller

Why is my UISearchDisplayController accessing an illegal cell / indexPath?


I have a table view with a search bar. Initially, the table view shows all (10) items. When I select a cell, a detail view is pushed on the navigation controller stack, and I can then go back to the table view by tapping the Back button. As long as I have not entered a search text yet, the table view shows all items, and I can go back and forth between the detail view and the table view indefinitely.

When I enter a text in the search bar, the table view is updated correctly with the self.searchDisplayController.searchResultsTableView (say it only shows 8 items now), that means

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

is called 8 times (section 0, rows 0 to 7). Fine.

I can then tap a cell, see the detail view, and go back to the table view showing the 8 items.

If I then select a cell in the table view still showing the 8 items (the same cell as before or a different one, does not matter), I again see the detail view, and then tap the "Back" button,

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

is called for section 0, row 8, which is not existing, since the searchResultsTableView still only shows the 8 items (rows 0 to 7) from the search.

I don't really understand what is going on:

  • the search works correctly,
  • but cellForRowAtIndexPath is called with a "wrong" indexPath

EDIT: Removed assumption about mixing up the two table views - everything seems to be in the correct place, but cellForRowAtIndexPath is still called for row 8. Also note that it's ALWAYS row 8.

EDIT 2: Here is the cellForRowAtIndexPath. "Zeichen" is a DAO, the getZeichenForIndexPath:indexPath returns the correct instance from the search result.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchResultCell" ];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SearchResultCell"];
    }

    Zeichen *zeichen = [self getZeichenForIndexPath:indexPath];

    UIImage *img = [UIImage imageNamed:zeichen.filename];
    cell.imageView.image = img;

    cell.textLabel.text = [zeichen description];
    return cell;
}

Solution

  • I think you should control tableView == self.searchDisplayController.searchResultsTableView. This control should be in didSelectRowAtIndexPath: method as well.

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
          if(tableView == self.searchDisplayController.searchResultsTableView)
          {
                 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchResultCell" ];
                 if (cell == nil) {
                      cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SearchResultCell"];
                 }
          }
          else
          {
                UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" ];
                 if (cell == nil) {
                      cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
                 }
          }
        return cell;
    }
    

    other thought: [tableView dequeueReusableCellWithIdentifier:@"SearchResultCell" forIndexPath:indexPath] usage is more convenient, if you are initialize your table view in storyboard or nib (setting cell identifier in storyboard).