我有一个符合UISearchDisplayDelegate并包含UISearchBar的类。此视图负责允许用户轮询当前由Core Data管理的大约17,000个对象的存储。每次用户键入一个字符时,我都会创建一个SearchOperation(子类NSOperation)的实例,该实例查询Core Data以查找可能与搜索匹配的结果。搜索控制器中的代码类似于:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
// Update the filtered array based on the search text and scope in a secondary thread
if ([searchText length] < 3) {
[filteredList removeAllObjects]; // First clear the filtered array.
[self setFilteredList:NULL];
[self.tableView reloadData];
return;
}
NSDictionary *searchdict = [NSDictionary dictionaryWithObjectsAndKeys:scope, @"scope", searchText, @"searchText", nil];
[aSearchQueue cancelAllOperations];
SearchOperation *searchOp = [[SearchOperation alloc] initWithDelegate:self dataDict:searchdict];
[aSearchQueue addOperation:searchOp];
}
我的搜索非常直接。 SearchOperation是NSOperation的子类。我用以下代码覆盖了main方法:
- (void)main
{
if ([self isCancelled]) {
return;
}
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSPredicate *predicate = NULL;
predicate = [NSPredicate predicateWithFormat:@"(someattr contains[cd] %@)", searchText];
[fetchRequest setPredicate:predicate];
NSError *error = NULL;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
if (self.delegate != nil)
[self.delegate didFinishSearching:fetchResults];
[pool drain];
}
此代码有效,但它有几个问题。
这很慢。即使我在除UI线程之外的单独线程中进行搜索,查询17,000个对象显然不是最佳的。
如果我不小心,可能会发生崩溃。我将我的NSOperationQueue中的最大并发搜索数设置为1以避免这种情况。
我还能做些什么来加快搜索速度?我认为将所有17,000个对象预加载到内存中可能会有风险。必须有一种更智能的方法来进行此搜索,以便更快地将结果返回给用户。
答案 0 :(得分:1)
以树形式组织数据?这样你就可以轻松检查下一个字母是否有效...
编辑:更多地思考这个问题。如果您设置一个具有指针数组的树,该指针是每个支持的输入字符,您可以轻松地跳转到树中该点的数组中的正确位置,以查看树中是否存在另一个级别。它在内存使用方面会花费更多,但会非常快......
进一步编辑:如果您想节省大量内存,那么您可以轻松设置一个非常快速扫描的文件。如果考虑到树中每个级别节点都有固定数量的可能项目,那么您可以轻松地快速搜索文件中所需的位置。对于您输入的每个字符,这是O(1)。因此,您可以在O(n)中搜索用户输入的所有内容。
答案 1 :(得分:1)
您使用什么类型的持久性商店? SQLite还是Binary?
假设SQLite,您是否正在索引要搜索的列?
我猜您最初使用NSFetchedResultsController
权利显示数据?如果没有,为什么不呢? NSFetchedResultsController中的缓存将帮助极大地解决此问题。
如果您使用的是NSFetchedResultsController
,那么请更改搜索,以便不是每次都点击磁盘,而是点击内存中已有的数据。通过访问[myFetchController fetchedObjects]
数组,您可以使用NSPredicate
来过滤结果。这是第一封信。
从那里,您可以使用已经过滤的数组,并在每次按下新键时再次过滤它。这将使您在缩小搜索范围时加快搜索速度。
在这种情况下,您的初始搜索会很慢。但是,一旦你从输入的第一个字符进行了初始搜索,你就可以对该数组进行过滤,而不是回到磁盘,这应该是近乎瞬时的。
您可以通过以下方式改善初始搜索: