Filtering Data with NSPredicate

NSPredicates is the powerful technology that allows you to easily filter data, according to certain simple or complex conditions.

This is a very handy feature. For example, if we have an array filled with objects that have a property name, we can easily filter them by name in the following way:

NSPredicate *lFilter = [NSPredicate predicateWithFormat:@"name == %@", name];
NSArray* result = [collection filteredArrayUsingPredicate:lFilter];

Note that essentially, predicate is just an expression that evaluates to the boolean YES or NO values.

Client-side filtering

Data Abstract for Cocoa provides intensive predicates support for filtering rows in the data tables. DADataTable also provides a number of helper methods that make it easy to access sorted or filtered rows from the data table, such as the following:

// DADataTable.h

- (void)filterUsingPredicate:(NSPredicate *)predicate;

- (NSArray *)rowsFilteredUsingPredicate:(NSPredicate *)predicate;

- (NSArray *)rowsFilteredUsingPredicate:(NSPredicate *)predicate
                          sortedByField:(NSString *)sortField
                              ascending:(BOOL)ascending;

- (NSArray *)rowsFilteredUsingPredicate:(NSPredicate *)predicate
localizedCaseInsensitivelySortedByField:(NSString *)sortField
                              ascending:(BOOL)ascending;

All of these methods return NSArrays of filtered (and/or sorted) rows. These methods make it really easy to work with a local subset of the data without running an extra request against the server. For example:

// Simple equality

NSString *positionName = @"Sales Manager";
NSPredicate *condition = [NSPredicate predicateWithFormat:@"WorkerPosition == %@", positionName];
self.rows = [workersTable rowsFilteredUsingPredicate:condition];
[tableView reloadData];

// Between sample

NSArray *range = [NSArray arrayWithObjects: [NSNumber numberWithInt:115], [NSNumber numberWithInt:117], nil];
NSPredicate *condition = [NSPredicate predicateWithFormat: @"WorkerID BETWEEN %@", range];
self.rows = [workersTable rowsFilteredUsingPredicate:condition];
[tableView reloadData];


// IN sample

NSArray *list =
  [NSArray arrayWithObjects:
    [NSNumber numberWithInt:114],
    [NSNumber numberWithInt:116],
    [NSNumber numberWithInt:118], nil];

NSPredicate *condition = [NSPredicate predicateWithFormat: @"WorkerID IN %@", list];
self.rows = [workersTable rowsFilteredUsingPredicate:condition];
[tableView reloadData];

Server-side filtering

Using NSPredicate is also the most simple and convenient way for assembling Dynamic Where clauses. Instead of typing quite complex XML expressions, you can just compose the necessary predicate and then translate it into a DADynamicWhereClause which can be used in the GetDataTable* method call of the DARemoteDataAdapter class, as shown in the code below:

NSString *positionPattern = @"Representative";
NSPredicate *condition = [NSPredicate predicateWithFormat:@"WorkerPosition contains[cd] %@", positionPattern];
DADynamicWhereClause *clause = [DADynamicWhereClause dynamicWhereClauseWithPredicate:condition];
request = [rda beginGetDataTable:@"Workers"
                          select:[self fieldsToSelect]
                           where:clause
                           withBlock:^(DADataTable *table){
                              self.workersTable = table;
                              self.rows = [workersTable rows];
                              [tableView reloadData];
                           }];

The DADynamicWhereClause dynamicWhereClauseWithPredicate:condition here will produce the following Dynamic Where XML:

<?xml version="1.0" encoding="utf-16"?>
<query xmlns="http://www.remobjects.com/schemas/dataabstract/queries/5.0" version="5.0">
  <where>
    <binaryoperation operator="Like">
      <field>WorkerPosition</field>
      <constant type="String" null="0">%Representative%</constant>
    </binaryoperation>
  </where>
</query>

We also recommend to review some of our samples to see NSPredicate and the techniques shown here in action, for instance the DynamicWhere sample available in Console, Desktop or Mobile form.