Understand the ins and outs of the predicate NSPredicate in iOS in 30 minutes

Understand the ins and outs of the predicate NSPredicate in iOS in 30 minutes

I. Introduction

    In the interpretation of modern Chinese, a predicate is a term used to describe or judge the nature, characteristics or relationship between objects. In layman's terms, it describes the properties of things. In the Cocoa framework for iOS development, the NSPredicate class is provided. This class is usually called a predicate class. Its main function is to help query and retrieval in Cocoa, but it should be noted that the predicate does not actually provide query and retrieval support. It's a way of describing query retrieval conditions, just like a more standard general-purpose regular expression.

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

  • Comparison Predicates: Comparison predicates describe the state of a property that meets the conditions by using comparison operators.
  • Compound Predicates: Compound predicates are used to combine the results of multiple comparison predicates, taking the intersection, union or complement.

For comparison predicates, you can describe exact comparisons or fuzzy comparisons by range or inclusion. Note that any Cocoa class object can support predicates, but this class needs to implement the key-value-coding protocol.

Second, the application analysis of NSPredicate class

    NSPredicate provides methods for creating and parsing predicate objects, and it is also the base class for predicate-related classes in Cocoa. In our daily development, the application frequency of the NSPredicate class is also the highest.

    There are three ways to create a predicate object, namely, creating a predicate through a format string, creating a predicate directly through code, and creating a predicate through a template. NSPredicate provides the following functions for initialization:

//通过格式化字符串来进行谓词对象的初始化
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat argumentArray:(nullable NSArray *)arguments;
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat arguments:(va_list)argList;

Using format strings to initialize predicates is very flexible, but it should be noted that the syntax of predicate strings is different from that of regular expressions, which will be described later. The following is an example of predicate retrieval:

    //检索属性length为5的对象
    NSPredicate *  predicate = [NSPredicate predicateWithFormat:@"length = 5"];
    //对于这个数组中的字符串,即是检索字符串长度为5的元素
    NSArray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
    NSArray * result = [test filteredArrayUsingPredicate:predicate];
    //将打印@[@"swfas"]
    NSLog(@"%@",result);

In fact, you can also construct the format string like using the NSLog function, you can use %@,%d and other formatting characters to replace the actual value of the variable at runtime. At the same time, it should be noted that the predicate statement created by this format string will not be checked for syntax, and the wrong syntax will generate a runtime error, so be careful. There is a small detail to note. When formatting, if you use a variable, you don't need to add quotes. The parser will help you add it. If you use a constant, you need to escape it with escape characters, for example:

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

For attribute names, if formatting is also required, it should be noted that the % @ symbol cannot be used . This symbol will be automatically added with quotation marks by the parser during parsing. You can use %K. 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];
    //将打印@[@"swfas"]
    NSLog(@"%@",result);

    It is also a very common way to create a predicate object through a template. Different from the format string, the predicate template has only key names and no key values. The key value needs 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];
    //将打印@[@"swfas"]
    NSLog(@"%@",result);

Other properties and methods in NSPredicate are parsed as follows:

//创建一个总是验证通过(YES)或不通过(NO)的谓词对象
/*
如果创建的是验证通过的,则任何检索都会成功进行返回,否则任何检索都会失败不返回任何对象
*/
+ (NSPredicate *)predicateWithValue:(BOOL)value;
//自定义实现检索函数
/*
例如前面的示例也可以这样写
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;
//格式化字符串属性
@property (readonly, copy) NSString *predicateFormat;  
//当使用谓词模板来进行对象创建时,这个函数用来设置谓词模板中变量替换
- (instancetype)predicateWithSubstitutionVariables:(NSDictionary<NSString *, id> *)variables;
//检查一个Object对象是否可以通过验证
- (BOOL)evaluateWithObject:(nullable id)object; 
//用谓词模板进行对象的验证
- (BOOL)evaluateWithObject:(nullable id)object substitutionVariables:(nullable NSDictionary<NSString *, id> *)bindings;

3. Create a predicate object through code

    Earlier we said that there are three ways to create a predicate object. We have already introduced two of them. Creating a predicate object directly through code is the most complicated one. Creating predicate objects through code is very similar to creating Autolayout constraints through code. Through our previous introduction, predicates are actually using expressions to verify objects, and creating predicates with code is actually creating expressions with code.

1. First look at the NSComparisonPredicate class

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

    //创建左侧表达式对象 对应为键
    NSExpression * left = [NSExpression expressionForKeyPath:@"length"];
    //创建右侧表达式对象 对应为值
    NSExpression * right = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:5]];
    //创建比较谓词对象 这里设置为严格等于
    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];
    //将打印@[@"swfas"]
    NSLog(@"%@",result);

NSComparisonPredicateModifier is used to modify conditions. The enumeration is as follows:

typedef NS_ENUM(NSUInteger, NSComparisonPredicateModifier) {
    NSDirectPredicateModifier = 0, //直接进行比较操作
    NSAllPredicateModifier,  //用于数组或集合 只有当内部所有元素都通过验证时 集合才算通过
    NSAnyPredicateModifier  //同于数组或集合 当内部有一个元素满足时 集合算通过验证
};

Regarding NSAllPredicateModifier and NSAnyPredicateModifier, these two enumerations are specially used for the verification of array or collection type objects. ALL will verify all the elements, and the array or collection will pass the verification only after all of them pass. The collection is verified even if it passes, for example:

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

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

typedef NS_ENUM(NSUInteger, NSPredicateOperatorType) {
    NSLessThanPredicateOperatorType = 0, // 小于
    NSLessThanOrEqualToPredicateOperatorType, // 小于等于
    NSGreaterThanPredicateOperatorType, // 大于
    NSGreaterThanOrEqualToPredicateOperatorType, // 大于等于
    NSEqualToPredicateOperatorType, // 等于
    NSNotEqualToPredicateOperatorType, //不等于
    NSMatchesPredicateOperatorType, //正则比配
    NSLikePredicateOperatorType,  //Like匹配 与SQL类似
    NSBeginsWithPredicateOperatorType, //左边的表达式 以右边的表达式作为开头
    NSEndsWithPredicateOperatorType,//左边的表达式 以右边的表达式作为结尾
    NSInPredicateOperatorType, // 左边的表达式 出现在右边的集合中 
    NSCustomSelectorPredicateOperatorType,//使用自定义的函数来进行 验证
    NSContainsPredicateOperatorType, //左边的集合包括右边的元素
    NSBetweenPredicateOperatorType //左边表达式的值在右边的范围中 例如 1 BETWEEN { 0 , 33 }
};

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

//如果不需要特殊指定  这个枚举值也可以传0
typedef NS_OPTIONS(NSUInteger, NSComparisonPredicateOptions) {
    NSCaseInsensitivePredicateOption = 0x01, //不区分大小写
    NSDiacriticInsensitivePredicateOption = 0x02,//不区分读音符号
    NSNormalizedPredicateOption //比较前进行预处理 代替上面两个选项
};

2. NSExpression class

    The NSExpression class provides creation expressions, some of which are easy to understand below:

//通过格式化字符串创建表达式
+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat argumentArray:(NSArray *)arguments;
+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat, ...;
+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat arguments:(va_list)argList;
//直接通过对象创建常亮的表达式
+ (NSExpression *)expressionForConstantValue:(nullable id)obj; 
//创建变量表达式  验证时将从binding字典中进行替换
+ (NSExpression *)expressionForVariable:(NSString *)string; 
//将多个表达式组合成一个
+ (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;
//通过预定义的函数和参数数组来构建表达式对象  预定义的函数 可见dev开发文档
+ (NSExpression *)expressionForFunction:(NSString *)name arguments:(NSArray *)parameters;

3.NSCompoundPredicate类

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

//进行对象初始化
/*
typedef NS_ENUM(NSUInteger, NSCompoundPredicateType) {
    NSNotPredicateType = 0,   //取非
    NSAndPredicateType,  //与运算 
    NSOrPredicateType,   //或运算
};
*/
- (instancetype)initWithType:(NSCompoundPredicateType)type subpredicates:(NSArray<NSPredicate *> *)subpredicates;
//快速创建与运算
+ (NSCompoundPredicate *)andPredicateWithSubpredicates:(NSArray<NSPredicate *> *)subpredicates;
//快速创建或运算
+ (NSCompoundPredicate *)orPredicateWithSubpredicates:(NSArray<NSPredicate *> *)subpredicates;
//快速创建非运算
+ (NSCompoundPredicate *)notPredicateWithSubpredicate:(NSPredicate *)predicate;

4. Several usage scenarios of predicates

    Predicates are mainly used to validate the filtering of objects, arrays and collections. The validation of objects has been introduced earlier. Regarding the filtering functions of data and collections, the categories are as follows:

@interface NSArray<ObjectType> (NSPredicateSupport)
//不可变数组使用过滤器后返回新数组
- (NSArray<ObjectType> *)filteredArrayUsingPredicate:(NSPredicate *)predicate; 
@end

@interface NSMutableArray<ObjectType> (NSPredicateSupport)
//可变数组可以直接进行过滤操作
- (void)filterUsingPredicate:(NSPredicate *)predicate;
@end

@interface NSSet<ObjectType> (NSPredicateSupport)
//不可变集合过滤后返回新集合
- (NSSet<ObjectType> *)filteredSetUsingPredicate:(NSPredicate *)predicate;
@end

@interface NSMutableSet<ObjectType> (NSPredicateSupport)
//可变集合可以直接进行过滤操作
- (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. An overview of the formatting syntax of predicates

    The format string rule syntax in the predicate is listed below.

grammar rules significance
= left equals right
==     Left side equals right side, same as = 
>=     left is greater than or equal to right
=> The left side is greater than or equal to the right side and >= is the same
<= Left is less than or equal to right
=<     The left side is less than or equal to the right side is the same as <=
> Left is greater than right
< Left is smaller than right
!= left side is not equal to right side
<> Left side is not equal to right side is same as !=
BETWEEN    In the set where the left is on the right key BETWEEN @[ @1 ,@2]
TRUEPREDICATE A predicate that always returns YES
FALSEPREDICATE A predicate that always returns NO
AND logical and
&& Logical AND is consistent with AND
OR logical or
|| logical OR is consistent with OR
NOT logical not
!     Logical NOT is consistent with NOT
BEGINWITH The left side starts with the right side string
ENDWITH Left ends with right string
CONTAINS The collection on the left contains the elements on the right
LIKE     The left side is equal to the right side and wildcards such as * and ? can be used
MATCHES regular match
ANY For array collection classes, validate any of the elements
SOME Same as ANY
ALL For the array collection class, verify all elements in it
NONE The effect is equivalent to NOT (ANY)
IN     left in right set
SELF The object being authenticated itself

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325472012&siteId=291194637