You can create NSPredicate objects that describe exactly what you think is the truth and run each of your objects through the predicate to see if they match.
Creating a Predicate
One way to create predicate object is using query strings.
NSPredicate *predicate;
predicate = [NSPredicate predicateWithFormat: @"name == 'Herbie'"];
+predicateWithFormat: takes the provided string and builds a tree of objects behind the scenes that will be used to evaluate the predicate.
If a chunk of text in the predicate string is not quoted, it is treated as a key path. If it’s quoted, it’s treated as a literal string. You can use single quotes or double quotes (as long as they’re balanced). Usually, you’ll use single quotes; otherwise, you’ll have to escape each double quote in the string.
Evaluate the Predicate
BOOL match = [predicate evaluateWithObject: car];
NSLog (@"%s", (match) ? "YES" : "NO");
-evaluateWithObject: tells the receiving object (the predicate) to evaluate itself with the given object. In this case, it takes the car, applies valueForKeyPath: using name as the key path to get the name. Then, it compares it for equality to “Herbie”. If the name and “Herbie” are the same, -evaluateWithObject: returns YES, otherwise NO.
NSArray *cars = [garage cars];
for (Car *car in [garage cars]) {
if ([predicate evaluateWithObject: car]) {
NSLog (@"%@", car.name);
}
}
-filteredArrayUsingPredicate: is a category method on NSArray that will spin through the contents of the array, evaluate each object against a predicate, and accumulate objects that evaluate to YES into a new array that is returned:
NSArray *results;
results = [cars filteredArrayUsingPredicate: predicate];
NSLog (@"%@", results);
Format Specifiers
We can put varying stuff into our predicate format strings in two ways: format specifiers and variable names.
You can put in numerical values with %d and %f like you’re familiar with:
predicate = [NSPredicate predicateWithFormat: @"name == %@", @"Herbie"];
NSPredicate strings also let you use %K to specify a key path. This predicate is the same as the others, using name == 'Herbie' as the truth:
predicate =
[NSPredicate predicateWithFormat: @"%K == %@", @"name", @"Herbie"];
Using format specifiers is one way to have flexible predicates. The other involves putting variable names into the string, similar to environment variables:
predicateTemplate =
[NSPredicate predicateWithFormat: @"engine.horsepower > $POWER"];
varDict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: 150], @"POWER", nil];
predicate =
[predicateTemplate predicateWithSubstitutionVariables: varDict];
Operator
The syntax also supports parenthetical expressions (really!) and the AND, OR, and NOT logical operators or their C-looking equivalents &&, ||, and !.
predicate = [NSPredicate predicateWithFormat:
@"(engine.horsepower > 50) AND
(engine.horsepower < 200)"];