NSFetchedResultsController与搜索

17

如何最佳实践地过滤NSFetchedResultsController的数据?每次搜索栏文本变化时我需要重新初始化吗?

我正在使用一个UISearchDisplayControllers,并实现了:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString;

感谢。


你是如何处理表视图数据源方法的,以便表视图知道是否显示“过滤列表”的? - CraigH
这是我做的:https://dev59.com/wW855IYBdhLWcg3wNhd1#4856118 - Rob Cohen
1
这里的答案非常有帮助 https://dev59.com/wW855IYBdhLWcg3wNhd1#4481896 - acecapades
2个回答

17

Guy的答案代码与问题有什么不同? 我猜filterContentForSearchText:scope方法是由shouldReload方法调用的?

无论如何,在CoreDataBooks示例中添加了一些类似的代码以包括搜索。 在IB中为CoreDataBooks示例添加一个Search Display Controller。 然后,我在RootViewController.m中添加了以下代码:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
 NSInteger searchOption = controller.searchBar.selectedScopeButtonIndex;
 return [self searchDisplayController:controller shouldReloadTableForSearchString:searchString searchScope:searchOption];
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
 NSString* searchString = controller.searchBar.text;
 return [self searchDisplayController:controller shouldReloadTableForSearchString:searchString searchScope:searchOption];
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString*)searchString searchScope:(NSInteger)searchOption {

 NSPredicate *predicate = nil;
 if ([searchString length])
  if (searchOption == 0) // full text, in my implementation.  Other scope button titles are "Author", "Title"
   predicate = [NSPredicate predicateWithFormat:@"title contains[cd] %@ OR author contains[cd] %@", searchString, searchString];
  else
   // docs say keys are case insensitive, but apparently not so.
   predicate = [NSPredicate predicateWithFormat:@"%K contains[cd] %@", [[controller.searchBar.scopeButtonTitles objectAtIndex:searchOption] lowercaseString], searchString];
 [fetchedResultsController.fetchRequest setPredicate:predicate];

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  abort();
    }           

 return YES;
}

PS.回答Vivas的问题,使用UISearchDisplayController会为重叠的过滤列表自动创建新的表视图。您可以按照文档所示检查使用的tableView,但在最简单的设置中,它只是起作用,因为fetchedResultsController在搜索的表视图中显示过滤版本或在您的表视图中显示所有数据。


仍然有奇怪的行为...对象确实被过滤了,但是当我向下滚动表视图时,它会抛出异常,因为fetchController在特定索引处没有对象...可能出了什么问题?请帮忙。 - Vladimir Stazhilov
我找到了问题所在...当我获取筛选结果时,它们会以与配置相同的方式显示在tableView中,当我滚动到行号X时,实际行数比X小...我该怎么办... - Vladimir Stazhilov

9
显然这是一种更好的方法:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    self.savedSearchTerm = searchText;

    freshData = NO;
    if (searchText !=nil)
    {
            NSPredicate *predicate =[NSPredicate predicateWithFormat:@"name contains[cd] %@", searchText];
            [fetchedResultsController.fetchRequest setPredicate:predicate];
    }
    else
    {
            NSPredicate *predicate =[NSPredicate predicateWithFormat:@"All"];
            [fetchedResultsController.fetchRequest setPredicate:predicate];
    }

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
            // Handle error
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            exit(-1);  // Fail
    }           

    [self.tableView reloadData];

    //    [searchBar resignFirstResponder];   
    //    [_shadeView setAlpha:0.0f];

 }

5
应用程序文档指出,获取请求不应被更改 - 它们明确表示您不应更改谓词。 - Rog
1
@RogerNolan 你确定吗?请查看NSFetchedResultsController类参考:修改获取请求。这三个步骤对我来说很有效,我甚至修改了获取请求的谓词。 - ma11hew28
这是一个更改(我想)。无论如何,基本上指令是,如果您更改请求,则必须重新发出搜索。 - Rog
我已经编辑了示例,将exit(-1)调用更改为abort()。正如0xced所说,也许两者都不应该被执行,但在iOS上调用exit()绝对不是一个好主意;在调试时,建议使用abort() https://developer.apple.com/library/ios/qa/qa1561/。 - Vincent Gable
这仅适用于在现有的表视图中搜索。除此之外,这是一个非常小的代码更改,是一个很好的解决方案。太棒了,点赞! - user431791

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接