NSPredicate 100

Objective-C  and Cocoa (or more accurately Cocoa Touch) are seeing  surge in developer interest due in most part to the revenue potential of the iOS App Store. A lot has been made of Objective-C’s quarks and it’s true; like all other programming languages Objective-C has its oddities that might have made sense at one point but feel either strange or in some cases dated. Unfortunately, a lot of developers new to Objective-C seem to be having a lot of issues adapting to their newly adopted development stack, partly because they often try to wrongly apply concepts from other stacks to Cocoa inappropriately and partly because they just don’t know enough about Cocoa and the language to really work as efficiently as possible in the platform.  NSPredicate, in particular, is one of the classes that these developers simply do not use; presumably, because they are ignorant of it.

NSPredicate is designed to make searching sets of data based on constraints more efficient. Let’s look at a really simple example of how it might used:

NSArray* pokemon = @[@”pikachu”, @”charmander”, @”bulbasaur”, @”squirtle”];
NSPredicate* pokePredicate = [NSPredicate predicateWithFormat:@”SELF MATCHES @”charmander”];
NSArray* result = [pokemon filterUsingPredicate:pokePredicate];

Ok so what is happening there? We are defining a simple array of four strings. We are then creating a predicate based on the parameter of searching ‘SELF’ (a stand in for the objects that will be scanned themselves) with the parameter of ‘MATCHES’ (self explanatory) the object, in this case an NSString, ‘@”charmander”’. Some of you may be saying: ‘Big deal. I can do that with a for loop”. That’s correct. In fact, for this simple example the ‘for loop’ option isn’t too terrible:

 
for (NSString* aString in pokemon) {
if ([aString isEqualToString:@”charmander”]) {
NSArray* result = @[aString];
}
}

That works but is not very pretty. Additionally, Apple has put a lot into optimizing NSPredicate and in most cases for all but the simplest searches, NSPredicate will be significantly more efficient than any ‘for loop’ any of us could code.

That’s all well and good, but another great thing about NSPredicate is that it takes advantage of one of my favorite Objective-C features: blocks. That’s right, you can get the same search and filter power of NSPredicate but also be able to define your own filtering method via a block:

NSPredicate* pokePredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject,
NSDictionary* bindings) {
BOOL passedYourTest;
// do some testing / comparisons
return passedYourTest;
}];

Ok so that does not return an array like the first example, but it does show one of the other most commonly used features NSPredicate: testing a group of objects against some arbitrary parameters. Why would you bother doing this sort of thing with NSPredicate rather than a more traditional loop? You guessed it! Apple has optimized NSPredicate, however, your custom block can definitely slow things down if you are not careful.

This is just a simple example of what can be done with NSPredicate and I hope that at least some of you will take a look at the class’s documentation and give some thought as to how you can optimize and make your code more elegant with the help NSPredicate.  Comments? Questions? Find me on Google+ or Twitter.

Comments are closed.