我正在构建一个自定义的UITableViewController,它显示iPhone中的所有联系人,其行为类似于ABPeoplePickerNavigationController。这意味着它还支持搜索联系人。我使用代码here执行此操作。
我已使用Search Bar and Search Display Controller
实现了搜索功能,并且我遵循了此tutorial by appcoda。
由于我的NSArray是一个ABRecordRef
的数组,我filterContentForSearchText: scope:
的方法是这样的:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
ABRecordRef person = (__bridge ABRecordRef)evaluatedObject;
NSString * fullname = [self getFullnameOfRecord:person];
NSPredicate *tmpPredicate = [NSPredicate predicateWithFormat:@"self contains[c] %@", searchText];
if ([tmpPredicate evaluateWithObject:fullname]) {
return YES;
} else {
NSLog(@"tmpPredicate didn't match");
return NO;
}
}];
searchResults = [self.allContacts filteredArrayUsingPredicate:resultPredicate];
}
搜索结果很好,但由于这是一个非常大的数组,因此效果非常慢。有没有办法可以提高这种搜索机制的性能?
更新:正如@Eiko建议的那样,我尝试使用此代码替换内部NSPredicate:
NSRange range = [fullname rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.length > 0) {
return YES;
} else {
return NO;
}
但它并没有改善表现。
答案 0 :(得分:1)
您应该尝试使用分析器找到最弱的线, 但我认为问题是每次都会为每个条目评估谓词块。
我建议你为ABRecordRef创建自己的包装类(让我们说RecordWrapper),它将包含ABRecordRef与整个数据的链接并缓存一些常用的重要值(例如fullName),你可以获得加载联系人列表时一次。
然后,如果你有一个RecordWrapper *对象数组,你可以通过调用
进行过滤NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"fullName contains[c] %@", searchText];
searchResults = [self.allContactsWrappers filteredArrayUsingPredicate:resultPredicate];
这应该会显着提高过滤速度。
答案 1 :(得分:0)
“非常大的阵列”?我猜联系人列表相当小,通常是< 1k元素。
话虽这么说,谓词的东西可能是溢价,而this回答简单的累积可能是最快的。我建议在真实设备上测试(和配置文件)。
我想创建谓词可能是一项代价高昂的操作(他们需要编译吗?),所以你可以重用它,甚至更好,只需在fullname
自己做一点“包含检查”(只是使用rangeOfString:options:
进行搜索,完全省略谓词。