Sunday 25 September 2011

NSPredicate with Object

Cocoa-Touch ships with an super-useful class that will help you search through your lists of objects just like they were coming from a database. The class is called NSPredicate which also works with Core Data. This is very powerful stuff, especially what you are working with data intensive applications.

Here Is How NSPredicate Works

First off, keep in mind that generally we are using NSArray to manage lists of objects in our apps. The objects that NSArray stores for us are made up of properties like name, length and whatever is required for the objects in question. NSPredicate works by defining queries that select objects from an array based on the properties of the objects in the array.
Here are the steps required to search arrays with NSPredicate:

Find or create an NSArray full of objects with interesting properties
Create an NSPredicate object with the search query that you want to use
You can use this NSPredicate object to either filter the array or create a new array with a subset of data

Essentially, these three steps are all it takes to filter an array. Of course, you will need some other pieces in place to do some meaningful work. Next, I will show you a concrete example of using NSPredicate with a custom class.

NSPredicate Search Example

Here Is The Type Of Object We Will Query

The first thing I did for this example was to create a custom class called Predicate_Data that could correspond to an individual row of data in a database.


Anyway, here is the class definition for Predicate_Data:

#import <Foundation/Foundation.h>

@interface Predicate_Data : NSObject {
    int primaryKey;
    NSString *name;
    NSNumber *rollNo;
}

@property(nonatomic, assign) int primaryKey;
@property(nonatomic, retain) NSString *name;
@property(nonatomic, retain) NSNumber *rollNo;

@end



Create Your NSArray & Fill It With Predicate_Data Objects

In effect, we are creating a list of objects that is a bit like a database table. Note here that listOfItems is declared as an NSMutableArray at the top of the file where this code would be located since it needs to stay in scope though-out the lifecycle of objects made from the class:
listOfItems = [[NSMutableArray alloc] init];

for(int i=0;i< 5;i++)
{
Predicate_Data *the_object = [[Predicate_Data alloc]init];
the_object.primaryKey = i;
the_object.name  = [NSString stringWithFormat:@"String%d",i];
the_object.rollNo = [NSNumber numberWithString:@"3102%d",i]; 
[listOfItems addObject:the_object];

[the_object release];
 
}

To summarize, we create an array and then create each object and add each object to the array. Here is what the results would look like if we were to present this array in a table view:

Get A Subset Of Data Instead!

So here is what you have been waiting for. To display a subset of the dataset you would need to code an NSPredicate using a query string. For instance, if we wanted to find out who in our dataset were programmers we could do something like this:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == 'String1'"];
[listOfItems filterUsingPredicate:predicate];


All you need to do is create the NSPredicate with our query and send the filterUsingPredicate message to your array using the NSPredicate object as an argument. If we tack this query to the end of our code and again run an app using a table view it would look like this:

 NSPredicate Query Examples:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"rollNo >= 31021"];
[listOfItems filterUsingPredicate:predicate];


Find everyone who has a name that begins with “T”:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH 'T'"];
[listOfItems filterUsingPredicate:predicate];


Other few examples on NSPredicate

Simple match

The simplest example is when you just need an exact match against a single value. This is a fairly meaningless example in this case but illustrates the basic technique:

    NSString *match = @"Kumar.";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF == %@", match];
    NSArray *results = [directoryContents filteredArrayUsingPredicate:predicate];


The query string is simply “SELF == %@” where SELF refers to the each element in the array. To use the predicate we apply it to the array of file names using filterArrayUsingPredicate:. In this trivial (and pointless) example the results array would contain a single string “Kumar.” assuming that file existed in the directory.

Wildcard match

To match using a wildcard string the query can use like instead of the comparison operator and include the “*”  (match zero or more characters) or “?” (match exactly 1 character) as wildcards as follows:
    NSString *match = @"Anand*.";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like %@", match];
    NSArray *results = [directoryContents filteredArrayUsingPredicate:predicate];



In this case the results array would contain the filenames that match Anand*. (e.g. Anand-001., Anand-002., etc.).





No comments:

Post a Comment