我正在使用NSPredicate过滤NSArray并将过滤后的数组用于我的UITableView。 当用户在UITextField中输入文本时,我正在使用此过滤。因此,每次UITextField中的文本发生更改时,我都会调用我的过滤器函数。
看起来像这样:
NSArray *hugeArray = ...;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", input];
_resultArray = [hugeArray filteredArrayUsingPredicate:predicate];
[_myTableView reloadData];
当我使用带有大量对象的NSArray时,输入变得非常慢(UI中的完整输入变慢)。 是否有可能获得更好的性能或在后台运行已过滤的命令?
不应阻止在UITextField中写入内容。当UITableView在输入后很短的时间后刷新它可能没问题。
答案 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];
});
});