Question

So, using storyboard you can create a segue from the UITableViewCell from the first tableViewController to a detailViewController.

Not too complicated, however, when a UISearchBarDisplayController is introduced into the storyboard mix, how can you segue the results cell to the detailViewController?

I am able to search without a problem, I followed this tutorial: http://clingingtoideas.blogspot.com/2010/02/uitableview-how-to-part-2-search.html

All I can do is select a row from the search, it turns blue and doesn't go to the detailViewController.

I have implemented the method prepareForSegue, which works for the non searched cells, but can't figure out this one.

Was it helpful?

Solution 3

Ok I think I got it, it seems like a bit of a hack but it works for my purposes:

I am using storyboard: I have a UITableview controller with UISearchBarDisplayController directly on top of it. No code just drag and drop.

From there, I followed this tutorial to get the search bar to search correctly http://clingingtoideas.blogspot.com/2010/02/uitableview-how-to-part-2-search.html

However prepareForSegue: would only let me display a cell from the original array, not with the search array.

So I used didSelectRowAtIndexPath:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (savedSearchTerm) {
    searchRowSelected = indexPath.row;  //<-- the trick that worked
    [self performSegueWithIdentifier:@"ShowDetail" sender:self];
}
}

searchRowSelected is an int variable that I declared at the top of the class.

didSelectRowAtIndexPath: knew which row I was selecting, but prepareForSegue didn't. Thats why I needed that variable.

This is how I used it in prepareForSegue:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:@"ShowDetail"]) {

    dvc = [segue destinationViewController];

    NSIndexPath* path = [self.tableView indexPathForSelectedRow];
    int row = [path row];

    if (savedSearchTerm){   //set the detailViewController with the searched data cell 
        myDataClass* c = [searchResults objectAtIndex:searchRowSelected];
        dvc.myDataClass = c;
    }else{    //set the detailViewController with the original data cell
       myDataClass* c = [array objectAtIndex:row];
       dvc.myDataClass = c;
   }
}
}

Also use this code to clean up savedSearchTerm

-(void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller{
    [self setSavedSearchTerm:nil];
}

If anyone has a better solution I'm all ears :)

OTHER TIPS

Here's the solution that's based on the comment by @James Chen. Also using a different IndexPath depending on which state the table is in.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

    if ([[segue identifier] isEqualToString:@"toDetail"]) {

        Person *person = nil;

        if (self.searchDisplayController.active == YES) {
            NSIndexPath *indexPath = indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
            NSLog(@"segue - section: %d, row: %d", indexPath.section, indexPath.row);

            person = [self.filteredPersonArray objectAtIndex:indexPath.row];
        }
        else {
            NSIndexPath *indexPath = indexPath = [self.tableView indexPathForSelectedRow];
            NSLog(@"segue - section: %d, row: %d", indexPath.section, indexPath.row);

            person = [self.personArray objectAtIndex:indexPath.row];
        }

        [[segue destinationViewController] setPerson:person];   

    }
}

I tried your solution and found that prepareForSegue is called twice due to the life cycle and didSelect... -> performSegueWithIdentifier.

  1. self:prepareForSegue: object on destination controller is set (with wrong index) because
  2. dest:viewDidLoad: the destination controller view is loaded after which
  3. self:didSelectRow...: the index is known and properly set.
  4. self:prepareForSegue: object is now correct but has no side effect.

I then focused on didSelect... and came up with this solution where I deleted the segue and pushed the view programmatically:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    DestTableViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"DestViewController"];

    CustomObj *custObj = nil;

    if (tableView == self.searchDisplayController.searchResultsTableView) {
        custObj = [filteredListContent objectAtIndex:indexPath.row];
    } else {
        storeToDetail = [self.fetchedResultsController objectAtIndexPath:indexPath];
    }

    controller.custObj = custObj;

    [self.navigationController setNavigationBarHidden:NO];
    [self.navigationController pushViewController:controller animated:YES];
    // presentViewController::animated:completion is always full screen (see problem below)
}

I then experienced some problems going back because I follow a segue from a mapView, which lead to:

//DestinationViewController
- (IBAction)back:(id)sender
{
    [self.navigationController popToRootViewControllerAnimated:YES]; // list
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; // map
}

which is not the way to do it but for now it works.

However, the first part is easy and clean, and maybe it works for you too?!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top