如何使用NSFetchedResultsController和UISearchDisplayController

14

我正在使用Core Data创建iPhone应用程序。

首先,同时使用NSFetchedResultsController和UISearchDisplayController获取结果是有意义的吗?您会推荐其他东西吗?

我已经尝试了相当长时间将NSFetchedResultController和UISearchDisplayController组合在一起。我一直在考虑在UIViewController的NSFetchedResultController中的(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption方法中设置NSPredicate。但这并没有很好地工作。

那么,您是否有想法如何为我的问题实现解决方案?感谢您提供答案或链接到好的教程。

编辑:

这是我的代码。 UISearchDisplayDelegate方法调用(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope方法,该方法应在NSFetchedResultController中设置谓词。 我还添加了NSFetchedResultController的代码。

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterContentForSearchText:searchString scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    NSString *query = self.searchDisplayController.searchBar.text;
    if (query && query.length) {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"Name contains[cd] %@", query];
        [fetchedResultsController.fetchRequest setPredicate:predicate];
    }

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

}


- (NSFetchedResultsController *)fetchedResultsController {

    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    /*
     Set up the fetched results controller.
    */
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    [aFetchedResultsController release];
    [fetchRequest release];
    [sortDescriptor release];
    [sortDescriptors release];

    return fetchedResultsController;
} 
3个回答

21

从你的代码中看,问题就出在那里了。我使用这种方法更改搜索时遇到了问题。修复方法:清除缓存!

假设你初始化了你的获取结果控制器如下所示。请注意cacheName属性。

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:[self fetchRequest] managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"UserSearch"];

当你改变谓词时,只需添加:

 [NSFetchedResultsController deleteCacheWithName:@"UserSearch"];

像魔法一样,它会很好地工作。

您还需要监视搜索显示控制器何时结束搜索,并清除谓词。

尽管这个主题看起来已经死了,但我在Google上找到了它,所以也许某个人会从中受益。 :)


1
这个解决方案虽然可行,但是代价相当昂贵,需要让获取结果的控制器多次访问持久存储。而且,如果你不打算使用缓存,为什么要指定一个呢?只需传递nil即可。然而,更好的解决方案是@psuedonick所提示的:让fetchedResultsController专注于其最擅长的工作,即管理获取的结果,并在fetchedObjects上使用filteredArrayUsingPredicate:来填充filteredListContent。 - Elise van Looij
2
澄清一下,如果您使用我描述的解决方案,则应该指定缓存:获取的结果控制器将需要它来存储fetchedObjects,以便可以通过filteredArrayUsingPredicate:有效地搜索它们。 - Elise van Looij
谢谢你,艾丽丝。我认为你的方法是可行的。稍后我会在另一篇文章中总结实现搜索显示控制器在表格视图控制器中的步骤。这个问题花费了我很多时间来寻找最佳实践。 - Philip007
我的帖子总结了在表视图中实现搜索的步骤,链接在这里:https://dev59.com/4mjWa4cB1Zd3GeqPt8VH - Philip007

7
根据文档,你需要使用谓词将结果过滤到数组中,或重新初始化fetchedResultsController。
重要提示:在初始化控制器后,您不得修改获取请求。例如,您不得更改基于谓词或排序顺序。
(-- NSFetchedResultsController

1

听起来你只是想获取和显示对象。在这种情况下,你不需要使用搜索显示控制器。搜索显示控制器用于与搜索栏一起使用,以帮助允许用户输入文本搜索您的内容。

通常,你使用获取结果控制器来辅助实现表视图数据源和委托方法。此外,你创建并使用一个获取请求来获取你的获取结果控制器。这都是样板代码(当你选择“使用核心数据进行存储”选项创建新项目时,可以查看Apple提供的模板代码)。

在获取请求中,你可以创建和指定谓词。这将允许你过滤你的表格显示的对象。例如:

// only fetch objects with myAttribute set to someValue
NSPredicate *pred = [NSPredicate predicateWithFormat:@"myAttribute == %@",someValue];
[fetchRequest setPredicate:pred];

好的,我之前没有明确提到我正在实现一个小搜索功能。我已经尝试将NSFetchedResultsController中的谓词设置为过滤结果,就像您发布的代码一样,但是什么也没有发生,没有找到任何对象。有什么想法为什么谓词不起作用吗?它只是在搜索字符串和对象名称之间进行了简单的比较。感谢您的帮助。 - burki
你应该添加关于谓词的详细信息或者提出一个新的问题。此外,在提问时展示你正在使用的代码总是很好的做法。 - gerry3

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