Filtering data is one of the essential tasks in computing. With all the data available today, we need to apply certain limits and constraints to actually make it usable. What use is it to be able to scroll down a list of literally thousands of list items when you really care about one or two of them? Filtering and searching information make up a significant part of our work day - each time you use Google, you’re applying a filter to the huge set of data we call the internet.
Even on your local computer, you use services like Spotlight or the search field in your mail application all the time. Apps that lack decent searching and filtering capabilities sometimes are really hard to use, so as developers we should spend some time on thinking how to allow users to filter the data they’re dealing with.
In this post, I am going to focus on ways to filter data. We won’t be looking at the UI side of things - this is something I’ll do in a subsequent blog post.
If you look at an arbitrary code base, chances are you’ll sooner or later run into a piece of code similar to this one:
1 2 3 4 5 6
It’s a straight-forward approach to filtering an array of items (in this case, we’re talking about books) using a rather simple
if-statement. Nothing wrong with this, but despite the fact we’re using a fairly simple expression here, the code is rather verbose. We can easily imagine what will happen in case we need to use more complicated selection criteria or a combination of filtering criteria.
Simple filtering with NSPredicate
Thanks to Cocoa, we can simplify the code by using NSPredicate.
NSPredicate is the object representation of an if-statement, or, more formally, a predicate.
Predicates are expressions that evaluate to a truth value, i.e.
false. We can use them to perform validation and filtering. In Cocoa, we can use
NSPredicate to evaluate single objects, filter arrays and perform queries against Core Data data sets.
Let’s have a look at how our example looks like when using
1 2 3
Much shorter and better readable!
Filtering with Regular Expressions
Regular Expressions can be used to solve almost any problem ;-) so it’s good to know you can use them in
NSPredicates as well. To use regular expressions in your
NSPredicate, you need to use the
Let’s filter all books that are about iPad or iPhone programming:
1 2 3
You need to obey some rules when using regular expressions in
NSPredicate: most importantly, you cannot use regular expression metacharacters inside a pattern set.
Filtering using set operations
Let’s for a moment assume you want to filter all books that have been published by your favorite publishers. Using the
IN operator, this is rather simple: first, we need to set up a set containing the publishers we’re interested in. Then, we can create the predicate and finally perform the filtering operation:
1 2 3 4
Advanced filtering thanks to KVC goodness
NSPredicate relies on key-value coding to achieve its magic. On one hand this means your classes need to be KVC compliant in order to be queried using
NSPredicate (at least the attributes you want to query). On the other hand, this allows us to perform some very interesting things with very little lines of code.
Let’s for example retrieve a list of books written by authors with the name “Mark”:
1 2 3
In case we’d want to return the value of one of the aggregate functions, we don’t need to use NSPredicate itself, but instead use KVC directly. Let’s retrieve the average price of all books on our shelf:
The Cocoa libraries provide some very powerful abstractions which can make your life and that of the people reading your code much easier. It pays off to know about them, so go ahead and browse the Cocoa documentation and hunt for those gems!
Apple’s NSPredicate programming guide provides an in-depth documentation for
NSPredicate containing all the things I didn’t cover in this post.
NSPredicate also plays an important role when querying data in Core Data, something we will need to have a look at in one of the next blog posts. Stay tuned!
The code for this post is available on my github page: get forking!