Filtering With NSPredicate
Using NSPredicates in general
NSPredicates is a 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];
let lFilter: NSPredicate = NSPredicate(format: "lastName = %@", surname)
var result: NSArray = collection.filteredArrayUsingPredicate(lFilter)
Note that essentially, predicate is just an expression that evaluates to the boolean YES or NO values.
Using NSPredicate for 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;
TODO
All of these methods return NSArrays of filtered (or/and 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 method dynamicWhereClauseWithPredicate:condition of DADynamicWhereClause 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 either our DynamicWhere sample or our PCTrade sample to see NSPredicate and the techniques shown here in action.