Search code examples
objective-cuitableviewuisplitviewcontrollermaster-detailuisearchcontroller

UISplitViewController using a UISearchController not passing objects to detailView while searching


I have a Master-Detail Application created, I implemented a UISearchController for the tableview.

The TableView and detailViews works correctly when the search is blank, but when searching the tableview shows the correctly filtered objects but fail to pass it to the detailView.

Any help would be greatly appreciated. thanks in advance.

#pragma mark -
#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [[self.fetchedResultsController sections] count];
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
        return [sectionInfo numberOfObjects];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    // Display the First Letter of the person's last name as section headings.
    //return [[[fetchedResultsController sections] objectAtIndex:section] name];
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];

    return [NSString stringWithFormat:@"%@", [sectionInfo name]];
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {

    if (index == 0) {
        // search item
        [tableView scrollRectToVisible:[[tableView tableHeaderView] bounds] animated:NO];
        return -1;
    }
    return index-1;
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    // Return the array of section index titles
    NSArray *searchArray = [NSArray arrayWithObject:UITableViewIndexSearch];
    return [searchArray arrayByAddingObjectsFromArray:self.fetchedResultsController.sectionIndexTitles];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //self.navigationItem.leftBarButtonItem = self.editButtonItem;

    //UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];
    //self.navigationItem.rightBarButtonItem = addButton;
    self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];

    self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Printers" style:UIBarButtonItemStylePlain target:nil action:nil];

    //instantiate a search results controller for presenting the search/filter results (will be presented on top of the parent table view)
    UITableViewController *searchResultsController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];

    searchResultsController.tableView.dataSource = self;

    searchResultsController.tableView.delegate = self;

    //instantiate a UISearchController - passing in the search results controller table
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];

    //this view controller can be covered by theUISearchController's view (i.e. search/filter table)
    self.definesPresentationContext = YES;


    //define the frame for the UISearchController's search bar and tint
    self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);

    self.searchController.searchBar.tintColor = [UIColor whiteColor];

    //add the UISearchController's search bar to the header of this table
    self.tableView.tableHeaderView = self.searchController.searchBar;


    //this ViewController will be responsible for implementing UISearchResultsDialog protocol method(s) - so handling what happens when user types into the search bar
    self.searchController.searchResultsUpdater = self;


    //this ViewController will be responsisble for implementing UISearchBarDelegate protocol methods(s)
    self.searchController.searchBar.delegate = self;
}

    #pragma mark - UISearchResultsUpdating

    -(void)updateSearchResultsForSearchController:(UISearchController *)searchController {

        //get search text from user input

        [NSFetchedResultsController deleteCacheWithName:@"Master"];

        // Init a fetch request
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
        [fetchRequest setEntity:entity];

        // Apply an ascending sort for the color items
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"printer" ascending:YES selector:@selector(caseInsensitiveCompare:)];
        NSArray *descriptors = [NSArray arrayWithObject:sortDescriptor];
        [fetchRequest setSortDescriptors:descriptors];

        // Recover query
        query = self.searchController.searchBar.text;
        if (query && query.length) fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(printer contains[cd] %@)",query];


        // Init the fetched results controller
        NSError *error;

        self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"fLetter" cacheName:@"Master"];

        self.fetchedResultsController.delegate = self;

        if (![[self fetchedResultsController] performFetch:&error]) NSLog(@"Error: %@", [error localizedDescription]);


        //now that the tableSections and tableSectionsAndItems properties are updated, reload the UISearchController's tableview
        [((UITableViewController *)self.searchController.searchResultsController).tableView reloadData];
    }

       - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"showDetail"])
    {
        NSLog(@"showDetail segue was called...");

        if ([self.searchController.searchBar.text isEqualToString:@""])
        {
            NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
            Event *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
            DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
            [controller setDetailItem:object];
            controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
            controller.navigationItem.leftItemsSupplementBackButton = YES;
            NSLog(@"Search Predicate was blank, and the code came here...");

        }
        else
        {

            NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
            Event *object = [self.fetchedResultsController.fetchedObjects filteredArrayUsingPredicate:self.searchPredicate][indexPath.row];
            DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
            [controller setDetailItem:object];
            controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
            controller.navigationItem.leftItemsSupplementBackButton = YES;

        NSLog(@"Searching: section %ld row %ld", (long)indexPath.section, (long)indexPath.row);
        NSLog(@"searchPredicate %@", self.searchPredicate);            }
        [self.searchController.searchBar setText:@""];
    }
}

Solution

  • NSIndexPath *indexPath = [self.fetchedResultsController.fetchedObjects filteredArrayUsingPredicate:self.searchPredicate][indexPath.row];
    

    I am quite sure problem is in this line. Where you are getting the most right indexPath I mentioned in the line above?

    When you are searching and selecting from a tableView, tableView always return a selected row so use

    NSIndexPath *indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow]; 
    

    Instead of

    NSIndexPath *indexPath = [self.fetchedResultsController.fetchedObjects filteredArrayUsingPredicate:self.searchPredicate][indexPath.row];