SoFunction
Updated on 2025-04-04

30 minutes to quickly help you understand the predicate in iOS NSPredicate

1. Introduction

In modern Chinese interpretation, predicates are terms used to describe or judge the nature, characteristics, or relationships between objects. In layman's terms, it describes the properties of things. In the iOS development Cocoa framework, there is a NSPredicate class, which is usually also a predicate class. Its main function is to help query and retrieve in Cocoa. However, it should be noted that in essence, predicates do not provide support for query and retrieval. It is a way to describe query search conditions, just like a more standard and general regular expression.

The predicates provided by NSPredicate can be divided into two categories: comparative predicates and compound predicates.

  • Comparative Predicates: Comparative predicates describe the status of the attributes that meet the criteria by using the comparison operator.
  • Compound predicates: Compound predicates are used to combine the results of multiple comparison predicates, take intersections, union or complementary sets.

For comparison predicates, accurate comparisons can be described or fuzzy comparisons can be performed through scope or inclusion, etc. It should be noted that any Cocoa class object can support predicates, but this class requires the implementation of key-value-coding protocol.

2. Application analysis of NSPredicate class

NSPredicate provides methods for creating predicate objects and parsing predicate objects. It is also the base class in Cocoa's class about predicates. In our daily development, the NSPredicate class is also the most frequently applied.

There are three ways to create predicate objects, namely, create predicates by formatting strings, create predicates directly through code, and create predicates through templates. NSPredicate provides the following functions for initialization:

//Initialize predicate objects by formatting strings+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat argumentArray:(nullable NSArray *)arguments;
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat arguments:(va_list)argList;

Using formatted strings to initialize predicates is very flexible, but it should be noted that the syntax and regular expression of predicate strings are different. There will be a specific introduction later. Here is an example of predicate search:

 //Retrieve an object with a property length of 5 NSPredicate * predicate = [NSPredicate predicateWithFormat:@"length = 5"];
 //For the string in this array, it is to search for elements with a length of 5 strings NSArray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
 NSArray * result = [test filteredArrayUsingPredicate:predicate];
 //The @[@"swfas"] will be printed NSLog(@"%@",result);

In fact, you can also format strings like using NSLog functions. You can use %@, %d and other format characters to replace them with the actual value of the variable at runtime. At the same time, it is also necessary to note that predicate statements created by formatting strings will not undergo syntax checks. Incorrect syntax will produce runtime errors, so be extra careful. There is a small detail to note. When formatting, if you are using variables, you don’t need to add quotes. The parser will help you add them. If you use constants, you need to escape characters, for example:

NSPredicate * predicate = [NSPredicate predicateWithFormat:@"name = %@ && age = \"25\"",name];

For attribute names, if they also need to be formatted, you need to be careful not to use the %@ symbol. This symbol will be automatically quoted by the parser during parsing. %K can be used. The example is as follows:

 NSString * key = @"length";
 NSPredicate * predicate = [NSPredicate predicateWithFormat:@"%K = 5",key];
 NSArray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
 NSArray * result = [test filteredArrayUsingPredicate:predicate];
 //The @[@"swfas"] will be printed NSLog(@"%@",result);

Creating predicate objects through templates is also a very common way. Unlike formatting strings, there are only key names and no key values ​​in the predicate template. The key values ​​need to be provided in the dictionary, for example:

 NSPredicate * predicate = [NSPredicate predicateWithFormat:@"length = $LENGTH"];
 predicate = [predicate predicateWithSubstitutionVariables:@{@"LENGTH":@5}];
 NSArray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
 NSArray * result = [test filteredArrayUsingPredicate:predicate];
 //The @[@"swfas"] will be printed NSLog(@"%@",result);

Other properties and methods in NSPredicate are parsed as follows:

//Create a predicate object that always passes (YES) or does not pass (NO)/*
 If the created is validated, any search will be returned successfully, otherwise any search will fail without returning any object
 */
+ (NSPredicate *)predicateWithValue:(BOOL)value;
//Customize the search function/*

For example, the previous example can also be written like this

NSPredicate * predicate = [NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
 if ([evaluatedObject length]==5) {
 return YES;
 }
 return NO;
 }];
*/
+ (NSPredicate*)predicateWithBlock:(BOOL (^)(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings))block;
//Format string attribute@property (readonly, copy) NSString *predicateFormat; 
//When using predicate templates to create objects, this function is used to set variable replacement in predicate templates- (instancetype)predicateWithSubstitutionVariables:(NSDictionary<NSString *, id> *)variables;
//Check whether an Object object can pass verification- (BOOL)evaluateWithObject:(nullable id)object; 
//Use predicate templates to verify objects- (BOOL)evaluateWithObject:(nullable id)object substitutionVariables:(nullable NSDictionary<NSString *, id> *)bindings;

3. Create predicate objects through code

We have mentioned earlier that there are three ways to create predicate objects, and we have introduced two of them. Creating predicate objects directly through code is the most complex one. Creating predicate objects through code is very similar to creating Autolayout constraints through code. Through our introduction before, predicates actually use expressions to verify objects, and using code to create predicates actually use code to create expressions.

1. Let’s look at the NSComparisonPredicate class first

This class is a subclass of NSPredicate, which is used to create predicates for comparison types. For example, use the following code to override the above example:

 //Create the left expression object corresponding to the key NSExpression * left = [NSExpression expressionForKeyPath:@"length"];
 //Create the right expression object corresponding to the value NSExpression * right = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:5]];
 //Create a comparison predicate object. Here it is set to strictly equal to NSComparisonPredicate * pre = [NSComparisonPredicate predicateWithLeftExpression:left rightExpression:right modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:NSCaseInsensitivePredicateOption];
 NSArray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
 NSArray * result = [test filteredArrayUsingPredicate:pre];
 //The @[@"swfas"] will be printed NSLog(@"%@",result);

NSComparisonPredicateModifier is used to modify the condition, and the enumeration is as follows:

typedef NS_ENUM(NSUInteger, NSComparisonPredicateModifier) {
 NSDirectPredicateModifier = 0, //Directly perform comparison operations NSAllPredicateModifier, // Used for arrays or collections. The set is considered to be passed only when all internal elements pass the verification. NSAnyPredicateModifier //Same as an array or collection When an element inside satisfies the collection calculation passes verification};

Regarding NSAllPredicateModifier and NSAnyPredicateModifier, these two enumerations are specifically used for verification of array or collection type objects. ALL will verify all elements in it. After all, the array or collection will be considered to be passed. ANY will be considered to be passed as long as one element is passed, the array or collection will be considered to be passed, for example:

 NSPredicate * pre = [NSPredicate predicateWithFormat:@"ALL length = 5"];
 NSArray * test = @[@[@"aaa",@"aa"],@[@"bbbb",@"bbbbb"],@[@"ccccc",@"ccccc"]];
 NSArray * result = [test filteredArrayUsingPredicate:pre];
 //The @[@[@"ccccc",@"ccccc"]] will be printed NSLog(@"%@",result);

The NSPredicateOperatorType enum is used to set the operator type, as follows:

typedef NS_ENUM(NSUInteger, NSPredicateOperatorType) {
 NSLessThanPredicateOperatorType = 0, // Small NSLessThanOrEqualToPredicateOperatorType, // Less than or equal to NSGreaterThanPredicateOperatorType, // Greater than NSGreaterThanOrEqualToPredicateOperatorType, // Greater than or equal to NSEqualToPredicateOperatorType, // equal to NSNotEqualToPredicateOperatorType, //Not equal to NSMatchesPredicateOperatorType, // Regular comparison NSLikePredicateOperatorType, //Like matching is similar to SQL NSBeginsWithPredicateOperatorType, //The expression on the left starts with the expression on the right as the beginning NSEndsWithPredicateOperatorType,//The expression on the left ends with the expression on the right as the end NSInPredicateOperatorType, // The expression on the left appears in the collection on the right NSCustomSelectorPredicateOperatorType,//Use custom functions to verify NSContainsPredicateOperatorType, //The set on the left includes the elements on the right NSBetweenPredicateOperatorType //The value of the expression on the left is in the range on the right, for example 1 BETWEEN { 0 , 33 }};

The NSComparisonPredicateOptions enumeration is used to set the comparison method as follows:

//If you do not need to specify this enum value, you can also pass 0typedef NS_OPTIONS(NSUInteger, NSComparisonPredicateOptions) {
 NSCaseInsensitivePredicateOption = 0x01, //Case insensitive NSDiacriticInsensitivePredicateOption = 0x02,//No distinction between pronunciation marks NSNormalizedPredicateOption //Pre-process before comparison instead of the above two options};

kind

The NSExpression class provides the creation of expressions, and the following lists some of the easy-to-understand methods:

//Create expressions by formatting string+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat argumentArray:(NSArray *)arguments;
+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat, ...;
+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat arguments:(va_list)argList;
//Create a constant-bright expression directly through the object+ (NSExpression *)expressionForConstantValue:(nullable id)obj; 
//Create variable expressions and replace them from the binding dictionary when verifying.+ (NSExpression *)expressionForVariable:(NSString *)string; 
//Combine multiple expressions into one+ (NSExpression *)expressionForAggregate:(NSArray<NSExpression *> *)subexpressions;
+ (NSExpression *)expressionForUnionSet:(NSExpression *)left with:(NSExpression *)right;
+ (NSExpression *)expressionForIntersectSet:(NSExpression *)left with:(NSExpression *)right;
+ (NSExpression *)expressionForMinusSet:(NSExpression *)left with:(NSExpression *)right;
+ (NSExpression *)expressionForSubquery:(NSExpression *)expression usingIteratorVariable:(NSString *)variable predicate:(NSPredicate *)predicate;
//Construct expression objects through predefined functions and parameter arrays Predefined functions Visible dev development documentation+ (NSExpression *)expressionForFunction:(NSString *)name arguments:(NSArray *)parameters;

kind

This class is also a subclass of the NSPredicate class. It uses logical relationships to combine multiple predicate objects, and is parsed as follows:

//Initialize object/*
 typedef NS_ENUM(NSUInteger, NSCompoundPredicateType) {
  NSNotPredicateType = 0, //Fetch Non-
  NSAndPredicateType, // and operation
  NSOrPredicateType, // or operation
 };
 */
- (instancetype)initWithType:(NSCompoundPredicateType)type subpredicates:(NSArray<NSPredicate *> *)subpredicates;
//Quick creation and operation+ (NSCompoundPredicate *)andPredicateWithSubpredicates:(NSArray<NSPredicate *> *)subpredicates;
//Quick creation or operation+ (NSCompoundPredicate *)orPredicateWithSubpredicates:(NSArray<NSPredicate *> *)subpredicates;
//Quickly create non-operation+ (NSCompoundPredicate *)notPredicateWithSubpredicate:(NSPredicate *)predicate;

4. Several scenarios of use of predicates

Predicates are mainly used to verify the filtering of objects, arrays and sets. Object verification is introduced earlier, and the filtering functions for data and collections are as follows:

@interface NSArray<ObjectType> (NSPredicateSupport)
//Immutable array returns a new array after using filters- (NSArray<ObjectType> *)filteredArrayUsingPredicate:(NSPredicate *)predicate; 
@end
@interface NSMutableArray<ObjectType> (NSPredicateSupport)
//Variable arrays can be filtered directly- (void)filterUsingPredicate:(NSPredicate *)predicate;
@end
@interface NSSet<ObjectType> (NSPredicateSupport)
//Return to the new collection after immutable collection filtering- (NSSet<ObjectType> *)filteredSetUsingPredicate:(NSPredicate *)predicate;
@end
@interface NSMutableSet<ObjectType> (NSPredicateSupport)
//The variable set can be filtered directly- (void)filterUsingPredicate:(NSPredicate *)predicate;
@end
@interface NSOrderedSet<ObjectType> (NSPredicateSupport)
- (NSOrderedSet<ObjectType> *)filteredOrderedSetUsingPredicate:(NSPredicate *)p;
@end
@interface NSMutableOrderedSet<ObjectType> (NSPredicateSupport)
- (void)filterUsingPredicate:(NSPredicate *)p;
@end

5. Overview of formatting grammar of predicates

The following lists the rules syntax for formatting strings in predicates.

Syntax Rules significance
= The left side is equal to the right side
==     The left side is equal to the right side, which is consistent with =
>=     The left side is greater than or equal to the right side
=> The left side is greater than or equal to the right side is consistent with >=
<= Left side is less than or equal to right side
=<     The left side is less than or equal to the right side is consistent with <=
> The left side is larger than the right side
< Left side is smaller than right side
!= The left side does not equal the right side
<> The left side does not equal the right side, which is consistent with !=
BETWEEN    On the left is in the right set key BETWEEN @[@1,@2]
TRUEPREDICATE The predicate that always returns YES
FALSEPREDICATE Predicate that always returns NO
AND Logic and
&& Logical and consistent with AND
OR Logical or
|| Logical or consistent with OR
NOT Logical non-logical
!     Logical non-consistent with NOT
BEGINWITH The left side begins with the right side string
ENDWITH The left ends with the right string
CONTAINS The left collection contains the right element
LIKE     The left side is equal to the right side and * and ? and other wildcards can be used
MATCHES Regular Match
ANY For array collection class, verify any element
SOME Consistent with ANY
ALL For array collection class, verify all elements in it
NONE Effects are equivalent to NOT (ANY)
IN     The left side is in the right side set
SELF The verified object itself

Summarize

The above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.