NSHipster

Cocoa is the envy of other standard libraries when it comes to querying and arranging information. With NSPredicate, NSSortDescriptor, and an occasional NSFetchRequest, even the most complex data tasks can be reduced into just a few, extremely-understandable lines of code.

Now, NSHipsters are no doubt already familiar with NSPredicate (and if you aren't, be sure to tune in next week!), but if we take a closer look at NSPredicate, we see that NSPredicate is actually made up of smaller, atomic parts: two NSExpressions (a left-hand value & a right-hand value), compared with an operator (e.g. <, IN, LIKE, etc.).

Because most developers only use NSPredicate by means of +predicateWithFormat:, NSExpression is a relatively obscure class. Which is a shame, because NSExpression is quite an incredible piece of functionality in its own right.

So allow me, dear readers, to express my respect and fascination with NSExpression:

Evaluating Math

The first thing you should know about NSExpression is that it lives to reduce terms. If you think about the process of evaluating an NSPredicate, there are two terms and a comparator, so those two terms need to simplify into something that the operator can handle—very much like the process of compiling a line of code.

NSExpression functions take a given number of sub-expression arguments. For instance, in the above example, to get the standard deviation of the collection, the array of numbers had to be wrapped with +expressionForConstantValue:. A minor inconvenience (which ultimately allows NSExpression to be incredibly flexible), but enough to trip up anyone trying things out for the first time.

Basic Arithmetic

Advanced Arithmetic

Bounding Functions

ceiling: - (the smallest integral value not less than the value in the array)

trunc: - (the integral value nearest to but no greater than the value in the array)

Functions Shadowing math.h Functions

So mentioned, because ceiling is easily confused with ceil(3). Whereas ceiling acts on an array of numbers, while ceil(3) takes a double (and doesn't have a corresponding built-in NSExpression function). floor: here acts the same as floor(3).

floor:

Random Functions

Two variations—one with and one without an argument. Taking no argument, random returns an equivalent of rand(3), while random: takes a random element from the NSExpression of an array of numbers.

random

random:

Binary Arithmetic

bitwiseAnd:with:

bitwiseOr:with:

bitwiseXor:with:

leftshift:by:

rightshift:by:

onesComplement:

Date Functions

now

String Functions

lowercase:

uppercase:

No-op

noindex:

Custom Functions

In addition to these built-in functions, it's possible to invoke custom functions in an NSExpression. This article by Dave DeLong describes the process.

The advantage here, over calling -factorial directly is the ability to invoke the function in an NSPredicate query. For example, a location:withinRadius: method might be defined to easily query managed objects nearby a user's current location.

As Dave mentions in his article, the use cases are rather marginal, but it's certainly an interesting trick to have in your repertoire.

Next week, we'll build on what we just learned about NSExpression to further explore NSPredicate, and everything it has hidden up its sleeves. Stay tuned!

Obscure Topics in Cocoa & Objective-C

NSPredicate is a Foundation class that specifies how data should be fetched or filtered. Its query language, which is like a cross between a SQL WHERE clause and a regular expression, provides an expressive, natural language interface to define logical conditions on which a collection is searched.