Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter huge NSArray

I'm filtering an NSArray with a NSPredicate and using the filtered array for my UITableView. I'm using this filtering when the user inputs text in a UITextField. So every time the text in the UITextField changes I'm calling my filter function.

It looks like this:

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

When I'm using a NSArray with a lot of objects the input becomes very slow (the complete input in the UI becomes slow). Is there any possibility to get a better performance or run the filtered command in background?

Writing something in the UITextField shouldn't be blocked. When the UITableView will be refreshed after a very short time after the input it may be ok.

like image 676
Sebastian Avatar asked Dec 12 '22 20:12

Sebastian


1 Answers

NSPredicate focuses on flexibility rather than speed. For an in-memory NSArray (i.e. not a Core Data relationship), you can generally get much better performance by just using a loop.

If it is still too slow, then there are several approaches:

  • Coalesce your requests. See Is there a simple way (in Cocoa/iOS) to queue a method call to run once in the next run loop? You can create a coalescing trampoline so that you only will update your list every few hundred milliseconds. That way if the user types very quickly, you don't re-filter the list every single chaacter.

  • Be smarter about filtering. If you just filtered for "bo" and you now want to filter for "bob", you know it's a subset of that previous list. You don't have to re-filter everything. Writing a good algorithm for this takes a little work but can dramatically improve performance.

  • Perform your filtering on an NSOperationQueue (easier to cancel than GCD, but GCD also works), and let the UI use KVO to notice when the filtered array changes.

  • Keep track of the actual changes (adds/deletes) while filtering. You shouldn't call reloadData on your table view if you can help it. You should perform inserts and deletes (insertRowsAtIndexPaths:). That avoids constantly churning your cells, and it also generally looks better. Again, the code is more complicated, but the improvements can be dramatic.

like image 157
Rob Napier Avatar answered Jan 14 '23 10:01

Rob Napier