我最近在我的一个项目中实现了这个功能(你的问题和另一个错误答案提示了该怎么做)。我尝试了Sergio的答案,但在实际设备上运行时遇到了异常问题。
是的,您需要创建两个fetch结果控制器:一个用于正常显示,另一个用于UISearchBar的表视图。
如果您只使用一个FRC(NSFetchedResultsController),则原始的UITableView(而不是搜索期间活动的搜索表视图)可能会在搜索时调用回调并尝试错误地使用已过滤的版本。 FRC,您将看到有关节或行数不正确的异常抛出。
这是我所做的:我有两个FRC作为属性可用:fetchedResultsController和searchFetchedResultsController。仅在进行搜索时才应使用searchFetchedResultsController(当取消搜索时,可以看到此对象被释放)。所有的UITableView方法都必须确定它将查询哪个表视图以及从哪个适用的FRC中提取信息。FRC委托方法也必须确定要更新哪个tableView。
令人惊讶的是,其中有多少是样板代码。
头文件中相关的部分:
@interface BlahViewController : UITableViewController <UISearchBarDelegate, NSFetchedResultsControllerDelegate, UISearchDisplayDelegate>
{
NSFetchedResultsController *fetchedResultsController_;
NSFetchedResultsController *searchFetchedResultsController_;
NSManagedObjectContext *managedObjectContext_;
NSString *savedSearchTerm_;
NSInteger savedScopeButtonIndex_;
BOOL searchWasActive_;
}
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, copy) NSString *savedSearchTerm;
@property (nonatomic) NSInteger savedScopeButtonIndex;
@property (nonatomic) BOOL searchWasActive;
实现文件中相关部分:
@interface BlahViewController ()
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSFetchedResultsController *searchFetchedResultsController;
@property (nonatomic, retain) UISearchDisplayController *mySearchDisplayController;
@end
我创建了一个有用的方法来检索正确的FRC,以便在处理所有UITableViewDelegate/DataSource方法时使用:
- (NSFetchedResultsController *)fetchedResultsControllerForTableView:(UITableView *)tableView
{
return tableView == self.tableView ? self.fetchedResultsController : self.searchFetchedResultsController;
}
- (void)fetchedResultsController:(NSFetchedResultsController *)fetchedResultsController configureCell:(UITableViewCell *)theCell atIndexPath:(NSIndexPath *)theIndexPath
{
}
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)theIndexPath
{
CallTableCell *cell = (CallTableCell *)[theTableView dequeueReusableCellWithIdentifier:@"CallTableCell"];
if (cell == nil)
{
cell = [[[CallTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CallTableCell"] autorelease];
}
[self fetchedResultsController:[self fetchedResultsControllerForTableView:theTableView] configureCell:cell atIndexPath:theIndexPath];
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger count = [[[self fetchedResultsControllerForTableView:tableView] sections] count];
return count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger numberOfRows = 0;
NSFetchedResultsController *fetchController = [self fetchedResultsControllerForTableView:tableView];
NSArray *sections = fetchController.sections;
if(sections.count > 0)
{
id <NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:section];
numberOfRows = [sectionInfo numberOfObjects];
}
return numberOfRows;
}
搜索栏的委托方法:
#pragma mark -
#pragma mark Content Filtering
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSInteger)scope
{
self.searchFetchedResultsController.delegate = nil;
self.searchFetchedResultsController = nil;
}
#pragma mark -
#pragma mark Search Bar
- (void)searchDisplayController:(UISearchDisplayController *)controller willUnloadSearchResultsTableView:(UITableView *)tableView;
{
self.searchFetchedResultsController.delegate = nil;
self.searchFetchedResultsController = nil;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[self.searchDisplayController.searchBar selectedScopeButtonIndex]];
return YES;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
[self filterContentForSearchText:[self.searchDisplayController.searchBar text]
scope:[self.searchDisplayController.searchBar selectedScopeButtonIndex]];
return YES;
}
在从FRC委托方法获取更新时,请确保使用正确的表视图:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
UITableView *tableView = controller == self.fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;
[tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type
{
UITableView *tableView = controller == self.fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;
switch(type)
{
case NSFetchedResultsChangeInsert:
[tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)theIndexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = controller == self.fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;
switch(type)
{
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:theIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self fetchedResultsController:controller configureCell:[tableView cellForRowAtIndexPath:theIndexPath] atIndexPath:theIndexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:theIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
UITableView *tableView = controller == self.fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;
[tableView endUpdates];
}
其他视图信息:
- (void)loadView
{
[super loadView];
UISearchBar *searchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 44.0)] autorelease];
searchBar.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.tableView.tableHeaderView = searchBar;
self.mySearchDisplayController = [[[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self] autorelease];
self.mySearchDisplayController.delegate = self;
self.mySearchDisplayController.searchResultsDataSource = self;
self.mySearchDisplayController.searchResultsDelegate = self;
}
- (void)didReceiveMemoryWarning
{
self.searchWasActive = [self.searchDisplayController isActive];
self.savedSearchTerm = [self.searchDisplayController.searchBar text];
self.savedScopeButtonIndex = [self.searchDisplayController.searchBar selectedScopeButtonIndex];
fetchedResultsController_.delegate = nil;
[fetchedResultsController_ release];
fetchedResultsController_ = nil;
searchFetchedResultsController_.delegate = nil;
[searchFetchedResultsController_ release];
searchFetchedResultsController_ = nil;
[super didReceiveMemoryWarning];
}
- (void)viewDidDisappear:(BOOL)animated
{
self.searchWasActive = [self.searchDisplayController isActive];
self.savedSearchTerm = [self.searchDisplayController.searchBar text];
self.savedScopeButtonIndex = [self.searchDisplayController.searchBar selectedScopeButtonIndex];
}
- (void)viewDidLoad
{
if (self.savedSearchTerm)
{
[self.searchDisplayController setActive:self.searchWasActive];
[self.searchDisplayController.searchBar setSelectedScopeButtonIndex:self.savedScopeButtonIndex];
[self.searchDisplayController.searchBar setText:savedSearchTerm];
self.savedSearchTerm = nil;
}
}
FRC创建代码:
- (NSFetchedResultsController *)newFetchedResultsControllerWithSearch:(NSString *)searchString
{
NSArray *sortDescriptors =
NSPredicate *filterPredicate =
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *callEntity = [MTCall entityInManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:callEntity];
NSMutableArray *predicateArray = [NSMutableArray array];
if(searchString.length)
{
[predicateArray addObject:[NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", searchString]];
if(filterPredicate)
{
filterPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:filterPredicate, [NSCompoundPredicate orPredicateWithSubpredicates:predicateArray], nil]];
}
else
{
filterPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicateArray];
}
}
[fetchRequest setPredicate:filterPredicate];
[fetchRequest setFetchBatchSize:20];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
aFetchedResultsController.delegate = self;
[fetchRequest release];
NSError *error = nil;
if (![aFetchedResultsController performFetch:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return aFetchedResultsController;
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController_ != nil)
{
return fetchedResultsController_;
}
fetchedResultsController_ = [self newFetchedResultsControllerWithSearch:nil];
return [[fetchedResultsController_ retain] autorelease];
}
- (NSFetchedResultsController *)searchFetchedResultsController
{
if (searchFetchedResultsController_ != nil)
{
return searchFetchedResultsController_;
}
searchFetchedResultsController_ = [self newFetchedResultsControllerWithSearch:self.searchDisplayController.searchBar.text];
return [[searchFetchedResultsController_ retain] autorelease];
}