Ich benutze UISearchResultsController
zum Filtern von Daten aus einer fetchedResultsController
. Hier ist der entsprechende Code:
Sur RootVieweController.h
:
@interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate, AdditionViewControllerDelegate, UISearchBarDelegate, UISearchDisplayDelegate> {
NSArray *filteredListContent;
NSString *savedSearchTerm;
NSInteger savedScopeButtonIndex;
BOOL searchIsActive;
}
@property (nonatomic, retain) NSArray *filteredListContent;
@property (nonatomic, copy) NSString *savedSearchTerm;
@property (nonatomic) NSInteger savedScopeButtonIndex;
@property (nonatomic) BOOL searchIsActive;
Sur RootViewController.m
:
-(void)viewDidLoad {
[snip]
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 300, 40)];
searchBar.delegate = self;
searchBar.scopeButtonTitles = [NSArray arrayWithObjects:@"Scope 1", @"Scope 2", nil];
[searchBar sizeToFit];
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.tableView.tableHeaderView = searchBar;
[searchBar release];
[self.tableView setContentOffset:CGPointMake(0, 40)];
UISearchDisplayController *searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
[self performSelector:@selector(setSearchDisplayController:) withObject:searchDisplayController];
[searchDisplayController setDelegate:self];
[searchDisplayController setSearchResultsDataSource:self];
[searchDisplayController setSearchResultsDelegate:self];
[searchDisplayController release];
self.filteredListContent = [NSMutableArray arrayWithCapacity:[[[self fetchedResultsController] fetchedObjects] count]];
if (self.savedSearchTerm) {
[self.searchDisplayController setActive:self.searchIsActive];
[self.searchDisplayController.searchBar setSelectedScopeButtonIndex:self.savedScopeButtonIndex];
[self.searchDisplayController.searchBar setText:savedSearchTerm];
self.savedSearchTerm = nil;
}
}
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
if (theTableView == self.searchDisplayController.searchResultsTableView) {
NSLog(@"Search Cells: %i", [self.filteredListContent count]);
return [self.filteredListContent count];
}
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
NSLog(@"Normal cells: %i", [sectionInfo numberOfObjects]);
return [sectionInfo numberOfObjects];
}
-(void)configureCell:(CustomTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
//Called from cellForRowAtIndexPath
Object *object = nil;
if (self.searchIsActive) {
object = [[self filteredListContent] objectAtIndex:[indexPath row]];
} else {
object = [fetchedResultsController objectAtIndexPath:indexPath];
}
[snip]
}
#pragma mark -
#pragma mark Search functions
-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope {
if ([scope isEqualToString:@"Scope 1"]) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"scope1 BEGINSWITH[cd] %@", searchText];
self.filteredListContent = [[[self fetchedResultsController] fetchedObjects] filteredArrayUsingPredicate:predicate];
} else {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"scope2 BEGINSWITH[cd] %@", searchText];
self.filteredListContent = [[[self fetchedResultsController]fetchedObjects] filteredArrayUsingPredicate:predicate];
}
}
#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)theTableView {
NSLog(@"Showing search results");
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:
[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
NSLog(@"Reloading for string");
return YES;
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
[self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
NSLog(@"Reloading for scope");
return YES;
}
-(void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
self.searchDisplayController.searchResultsTableView.rowHeight = 55;
self.searchIsActive = YES;
}
-(void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
self.searchIsActive = NO;
}
Im Simulator funktioniert das hervorragend. Aber auf einem Gerät stürzt es ab, wenn object = [[self filteredListContent] objectAtIndex:[indexPath row]];
de configureCell
beim Versuch, die searchResultsTableView anzuzeigen. Ich erhalte den Fehler [NSMutableArray objectAtIndex:]: index 7 beyond bounds for empty array
. Immer Index 7. Was übersehe ich hier?
--UPDATE--
Behoben: Umdrehen der searchIsActive
BOOL
zum Einschalten searchDisplayControllerDidBeginSearch
anstelle von searchDisplayControllerWillBeginSearch
y searchDisplayControllerWillEndSearch
anstelle von searchDisplayControllerDidEndSearch
. Dadurch wird verhindert, dass die Tabelle versucht, Zellen zu konfigurieren, die nicht vorhanden sind. Keine Ahnung, warum der Simulator das nicht bemerkt hat