4

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

它看起来像这样:

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

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

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

4

3 回答 3

12

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

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

  • 合并您的请求。请参阅是否有一种简单的方法(在 Cocoa/iOS 中)将方法调用排队以在下一个运行循环中运行一次?您可以创建一个合并蹦床,以便每隔几百毫秒更新一次列表。这样,如果用户键入非常快,您就不会重新过滤每个字符的列表。

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

  • 执行过滤NSOperationQueue(比 GCD 更容易取消,但 GCD 也可以),并让 UI 使用 KVO 来通知过滤后的数组何时发生变化。

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

于 2012-12-08T21:59:08.100 回答
1

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

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

Apple 文档中有关 NSSet、NSArray 和 NSDictionary 的更多信息

于 2016-01-11T14:53:14.300 回答
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];
          });
    });
于 2012-12-08T21:53:21.003 回答