prepareForSegue after UISearchDisplayController

2019-05-26 03:14发布

问题:

EDIT:

I just found: How to segue from a UISearchBarDisplayController result to a detailViewController

which I'll take a look at!


I'm combining a 'search bar and search display controller' with core data fetchedResultsController using storyboard. That is, I have to differentiate between:

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

and the case where I've just listed the results fetched from the data store.

However, I'm having trouble getting the right row (index path) in the following case:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"StoreDetails"]) {
        UINavigationController *navigationController = segue.destinationViewController;
        StoreDetailsTableViewController *controller = (StoreDetailsTableViewController *)navigationController.topViewController;
        controller.managedObjectContext = self.managedObjectContext;

        Store *storeToDetail = nil;
        NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];  // This gives wrong row when having searched using searchDisplayController
        NSLog(@"Row: %i", indexPath.row);                                                   // row is always 0
        if (self.tableView == self.searchDisplayController.searchResultsTableView) {
            storeToDetail = [self.filteredListContent objectAtIndex:indexPath.row];
        } else {
            storeToDetail = [self.fetchedResultsController objectAtIndexPath:indexPath];
        }

         controller.storeToDetail = storeToDetail;
    }
}

which is called after:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller       shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterContentForSearchText:searchString scope:@"All"];
    ...

with:

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    [self.filteredListContent removeAllObjects];

    for (Store *store in [self.fetchedResultsController fetchedObjects])
    {
        if ([scope isEqualToString:@"All"] || [store.name isEqualToString:scope])
        {
            NSComparisonResult result = [store.name compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
            if (result == NSOrderedSame)
            {
                [self.filteredListContent addObject:store];
            }
        }
    }
}

which is taken from Apple's TableSearch example.

The original problem is twofold:

1) self.tableView doesn't seem to be equal to self.searchDisplayController.searchResultsTableView is prepareForSegue

2) having searched the indexPath (row) is always 0.

I suppose I could use didSelectRow... instead or in combination, but I believe prepare... should be possible?! Also, when experimenting with didSelectRow... I'm sure how to pass the object from the relevant row to the destination controller. That is, I can get the correct indexPath in didSelectRow... but I only know how to get the segue destination in the preparFor...:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    Store *storeToDetail = nil;
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {
        storeToDetail = [self.filteredListContent objectAtIndex:indexPath.row];
    }
    else
    {
        storeToDetail = [self.fetchedResultsController objectAtIndexPath:indexPath];
    }

    // How to get segue destination controller and set object?!
    // Before doing:
    [self performSegueWithIdentifier:@"StoreDetails" sender:self];
}

Any help is much appreciated. Maybe a reference to a tutorial which shows how to combine theses things.

Thank you!

回答1:

In this case the senderargument of prepareForSegue:sender: is set to the table view cell initiating the segue.

Just add a property to your cells that holds the Store belonging to this cell and you don't have to do any of the index path or table view comparison dance.

You should end up with something as simple as

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    FooCell *cell = (FooCell *)[self.tableView dequeueReusableCellWithIdentifier:CELL_IDENTIFIER];
    Foo *foo = [self fooForIndexPath:indexPath];

    cell.foo = foo;
    // additional initialization

    return cell;
}

and

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"view detail"]) {
        DetailViewController *destViewController = segue.destinationViewController;
        destViewController.foo = [(FooCell *)sender foo];
    }
}


回答2:

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

{

if(self.filteredListContent)

{//NSLog(@"post filtered data";}

else

{//NSLog(@"post all";}

}



回答3:

You are using the wrong test.

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

This will always fail, you are asking if two different tableViews are different. The answer is always no.

However, you can test if the sender is from the searchResultsTableView.

NSIndexPath *searchIndexPathOfSelectedCell = [self.searchDisplayController.searchResultsTableView indexPathForCell:sender];

if (searchIndexPathOfSelectedCell) {
  ...