过滤巨大的NSArray

时间:2012-12-08 21:45:52

标签: ios nsarray nspredicate

我正在使用NSPredicate过滤NSArray并将过滤后的数组用于我的UITableView。 当用户在UITextField中输入文本时,我正在使用此过滤。因此,每次UITextField中的文本发生更改时,我都会调用我的过滤器函数。

看起来像这样:

NSArray *hugeArray = ...;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", input];
_resultArray = [hugeArray filteredArrayUsingPredicate:predicate];
[_myTableView reloadData];

当我使用带有大量对象的NSArray时,输入变得非常慢(UI中的完整输入变慢)。 是否有可能获得更好的性能或在后台运行已过滤的命令?

不应阻止在UITextField中写入内容。当UITableView在输入后很短的时间后刷新它可能没问题。

3 个答案:

答案 0 :(得分:12)

NSPredicate侧重于灵活性而非速度。对于内存中NSArray(即不是核心数据关系),只需使用循环就可以获得更好的性能。

如果它仍然太慢,那么有几种方法:

  • 合并您的请求。请参阅Is there a simple way (in Cocoa/iOS) to queue a method call to run once in the next run loop?您可以创建一个合并蹦床,这样您每隔几百毫秒就会更新一次列表。这样,如果用户输入速度非常快,则不会在每个字体中重新过滤列表。

  • 更聪明的过滤。如果您只是过滤了“bo”并且您现在想要过滤“bob”,那么您知道它是之前列表的子集。您不必重新过滤所有内容。为此编写一个好的算法需要一些工作,但可以显着提高性能。

  • NSOperationQueue上执行过滤(比GCD更容易取消,但GCD也有效),让UI使用KVO注意过滤后的数组何时发生变化。

  • 过滤时跟踪实际更改(添加/删除)。如果可以提供帮助,则不应在表格视图上调用reloadData。您应该执行插入和删除(insertRowsAtIndexPaths:)。这可以避免不断搅动细胞,而且通常看起来更好。同样,代码更复杂,但改进可能是戏剧性的。

答案 1 :(得分:1)

如果您仍想使用谓词,并且对象顺序不重要(意味着对象的索引无关紧要),您可以将NSArray转换为NSSet过滤一组(使用NSPredicate)比数组快得多。

NSSet *hugeSet = [NSSet setWithArray:hugeArray]
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", input];
NSSet *filteredSet = [hugeSet filteredSetUsingPredicate: predicate];

有关NSSet vs NSArray与https://stackoverflow.com/a/22503259/5315947

中的NSDictionary的更多信息

答案 2 :(得分:0)

我认为在后台运行它是解决方案。在另一个队列上执行查询,然后在主队列上重新加载表。使用GCD,它看起来像这样......

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", input];
        _resultArray = [hugeArray filteredArrayUsingPredicate:predicate];

          dispatch_async(dispatch_get_main_queue(), ^{
                [_myTableView reloadData];
          });
    });