Predicate

NSExpression的使用

2020-09-10  本文已影响0人  想聽丿伱說衹愛我

版本:iOS13.7

一、简介

表达式NSExpression是谓词NSPredicate实现的核心,常用于比较谓词NSComparisonPredicate,点击NSComparisonPredicate的使用了解。
调用expressionValueWithObject时,将对表达式求值,并返回一个可处理的值。
表达式可以是从常量到方法调用的任何内容。

表达式的结果指的是expressionValueWithObject的返回值。
表达式的参数对象指的是expressionValueWithObject传入的object或NSPredicate.evaluateWithObject传入的object。
表达式的bindings字典指的是expressionValueWithObject传入的context和NSPredicate.evaluateWithObject传入的bindings

二、NSExpression的API

@interface NSExpression : NSObject <NSSecureCoding, NSCopying>

//通过格式化字符串创建一个表达式
//字符串中的%@占位符将由arguments的元素替换
//详见说明1
+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat 
                         argumentArray:(NSArray *)arguments;
//通过格式化字符串创建一个表达式
//详见说明1
+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat, ...;
//通过格式化字符串创建一个表达式
//字符串中的%@占位符将由argList的元素替换
+ (NSExpression *)expressionWithFormat:(NSString *)expressionFormat
                             arguments:(va_list)argList;

//通过常量创建表达式
//NSExpression.constantValue为obj
+ (NSExpression *)expressionForConstantValue:(nullable id)obj; 
//通过参数对象创建表达式
//相当于[NSExpression expressionWithFormat:@"SELF"]
+ (NSExpression *)expressionForEvaluatedObject; 
//通过bindings字典的key创建表达式
//详见例1
+ (NSExpression *)expressionForVariable:(NSString *)string; 
//通过参数对象的keypath创建表达式
//详见例2
+ (NSExpression *)expressionForKeyPath:(NSString *)keyPath; 
//通过函数名创建表达式
//parameters里面为0至2个NSExpression
//详见例3
+ (NSExpression *)expressionForFunction:(NSString *)name arguments:(NSArray *)parameters;

//通过传入的表达式的结果的集合创建表达式
//详见例4
+ (NSExpression *)expressionForAggregate:(NSArray<NSExpression *> *)subexpressions;
//创建一个表达式,该表达式的结果为left和right结果的集合的并集
//该表达式的NSExpression.leftExpression为left,NSExpression.rightExpression为right
//详见例5
 + (NSExpression *)expressionForUnionSet:(NSExpression *)left with:(NSExpression *)right; 
//创建一个表达式,该表达式的结果为left和right结果的集合的交集
//详见例5
+ (NSExpression *)expressionForIntersectSet:(NSExpression *)left with:(NSExpression *)right;
//创建一个表达式,该表达式的结果为left和right结果的集合的析取(不太明白析取的意思~_~!)
+ (NSExpression *)expressionForMinusSet:(NSExpression *)left with:(NSExpression *)right;
//todo 
+ (NSExpression *)expressionForSubquery:(NSExpression *)expression 
                  usingIteratorVariable:(NSString *)variable 
                              predicate:(NSPredicate *)predicate; 
//创建一个表达式,表达式的结果为选择器的返回值
//target 选择器所属的对象
//name 选择器名
//parameters 选择器需要的参数,类型为NSArray<NSExpression *>
//详见例6
+ (NSExpression *)expressionForFunction:(NSExpression *)target 
                           selectorName:(NSString *)name 
                              arguments:(nullable NSArray *)parameters; 
//todo
+ (NSExpression *)expressionForAnyKey;
//通过block创建一个表达式,表达式的结果为block返回的值
//详见例7
+ (NSExpression *)expressionForBlock:(id (^)(id _Nullable evaluatedObject, NSArray<NSExpression *> *expressions, NSMutableDictionary * _Nullable context))block 
                           arguments:(nullable NSArray<NSExpression *> *)arguments;
//创建一个表达式,通过谓词评估结果的真假来决定使用trueExpression还是falseExpression
//谓词所需的评估对象为expressionValueWithObject传入的object
//详见例8
+ (NSExpression *)expressionForConditional:(NSPredicate *)predicate 
                            trueExpression:(NSExpression *)trueExpression
                           falseExpression:(NSExpression *)falseExpression; 

//通过表达式类型来初始化
//详见说明2
- (instancetype)initWithExpressionType:(NSExpressionType)type;
//初始化
- (nullable instancetype)initWithCoder:(NSCoder *)coder;

//表达式的类型 只读 详见说明2
@property (readonly) NSExpressionType expressionType;
//表达式的常数值 只读
@property (nullable, readonly, retain) id constantValue;
//表达式的参数对象的keyPath路径 只读
@property (readonly, copy) NSString *keyPath;
//表达式的函数名 只读
@property (readonly, copy) NSString *function;
//表达式的bindings字典的key 只读
@property (readonly, copy) NSString *variable;
//表达式要调用函数的对象 只读
@property (readonly, copy) NSExpression *operand; 
//表达式要调用函数的参数 只读
@property (nullable, readonly, copy) NSArray<NSExpression *> *arguments;   

//表达式的集合
@property (readonly, retain) id collection;
//表达式要满足的谓词
@property (readonly, copy) NSPredicate *predicate;
//集合表达式的左表达式
@property (readonly, copy) NSExpression *leftExpression;
//集合表达式的右表达式
@property (readonly, copy) NSExpression *rightExpression;

//条件表达式的谓词评估为真时的表达式
@property (readonly, copy) NSExpression *trueExpression;
//条件表达式的谓词评估为假时的表达式
@property (readonly, copy) NSExpression *falseExpression;

//表达式的block
@property (readonly, copy) id (^expressionBlock)(id _Nullable, NSArray<NSExpression *> *, NSMutableDictionary * _Nullable);

//使用参数对象和bindings字典来评估表达式,并返回结果
- (nullable id)expressionValueWithObject:(nullable id)object 
                                 context:(nullable NSMutableDictionary *)context;

//强制使用已安全解码的表达式以允许评估
- (void)allowEvaluation;

@end
NSExpression *exp = [NSExpression expressionWithFormat:@"%@" argumentArray:@[@"test"]];
等价于
NSExpression *exp = [NSExpression expressionWithFormat:@"%@", @"test"];

测试发现,当有多个%@时运行会崩溃,[NSExpression expressionWithFormat:@"a%@a", @"test"]这样写也会崩溃。

typedef NS_ENUM(NSUInteger, NSExpressionType) {
    //返回相同值的表达式
    NSConstantValueExpressionType = 0, 
    //返回参数对象本身的表达式
    NSEvaluatedObjectExpressionType, 
    //返回bindings字典中对应key的值的表达式
    NSVariableExpressionType,
    //返回参数对象的对应keyPath的值的表达式
    NSKeyPathExpressionType, 
    //返回函数返回值的表达式
    NSFunctionExpressionType, 
    //返回两表达式结果的并集的表达式
    NSUnionSetExpressionType, 
    //返回两表达式结果的交集的表达式
    NSIntersectSetExpressionType,
    //返回两表达式结果的析取的表达式
    NSMinusSetExpressionType , 
    //todo
    NSSubqueryExpressionType  = 13,
    //返回两表达式结果的集合的表达式
    NSAggregateExpressionType  = 14,
    //todo
    NSAnyKeyExpressionType  = 15,
    //返回block的返回值的表达式
    NSBlockExpressionType = 19,
    //根据谓词评估真假来决定的表达式
    NSConditionalExpressionType = 20
};
    NSExpression *left1 = [NSExpression expressionForVariable:@"key1"];
    NSExpression *right1 = [NSExpression expressionWithFormat:@"%@", @[@"aaa", @"bbb", @"ccc"]];
    NSComparisonPredicate *comparison1 = [NSComparisonPredicate predicateWithLeftExpression:left1 
                 rightExpression:right1 modifier:NSDirectPredicateModifier 
                 type:NSInPredicateOperatorType options:NSCaseInsensitivePredicateOption];
    NSLog(@"%@", [comparison1 predicateFormat]);
    BOOL success1 = [comparison1 evaluateWithObject:nil substitutionVariables:@{@"key1":@"aaa"}];
    NSLog(@"%@", @(success1));
输出:
$key1 IN[c] {"aaa", "bbb", "ccc"}
1

可以左表达式通过$声明了一个变量key1,该变量从substitutionVariables:传入的字典中取值。

    NSExpression *left1 = [NSExpression expressionForKeyPath:@"key1.key2"];
    NSExpression *right1 = [NSExpression expressionWithFormat:@"%@", @[@"aaa", @"bbb", @"ccc"]];
    NSComparisonPredicate *comparison1 = [NSComparisonPredicate predicateWithLeftExpression:left1 
                rightExpression:right1 modifier:NSDirectPredicateModifier 
                type:NSInPredicateOperatorType options:NSCaseInsensitivePredicateOption];
    NSLog(@"%@", [comparison1 predicateFormat]);
    BOOL success1 = [comparison1 evaluateWithObject:@{@"key1":@{@"key2":@"bbb"}}];
    NSLog(@"%@", @(success1));
输出:
key1.key2 IN[c] {"aaa", "bbb", "ccc"}
1

@{@"key1":@{@"key2":@"bbb"}}会调用valueForKeyPath:key1.key2取出值bbb

    NSExpression *left1 = [NSExpression expressionWithFormat:@"SELF"];
    //创建一个常数表达式
    NSExpression *sun = [NSExpression expressionForConstantValue:@[@2, @4, @6]];
    //sum:时需要arguments中存在一个常数值为NSNumber的集合的表达式
    NSExpression *right1 = [NSExpression expressionForFunction:@"sum:" arguments:@[sun]];
    NSComparisonPredicate *comparison1 = [NSComparisonPredicate predicateWithLeftExpression:left1 
            rightExpression:right1 modifier:NSDirectPredicateModifier 
            type:NSLessThanPredicateOperatorType options:NSCaseInsensitivePredicateOption];
    NSLog(@"%@", [comparison1 predicateFormat]);
    BOOL success1 = [comparison1 evaluateWithObject:@10];
    NSLog(@"%@", @(success1));
输出:
SELF <[c] sum:({2, 4, 6})
1
// name              meter array contents                               returns
// sum:              NSExpression instances representing numbers        NSNumber 
// multiply:by:      two NSExpression instances representing numbers    NSNumber

上面为官方注释,表示sum: 方法需要传入一个NSExpression实例,该实例的常数为numbers(NSNubmer的集合),并在调用expressionValueWithObject返回NSNumber。
multiply:by: 则表示要传入两个NSExpression实例,常数也为NSNubmer的集合,并返回NSNumber。

支持的函数方法
统计
sum:求和
count:个数
min:最小值
max:最大值
average:平均数
median:中位数
mode:众数(出现次数最多的数)
stddev:标准差
基本运算
add:to:
from:subtract:
multiply:by:
divide:by:
高级运算
modulus:by:模数
sqrt:开平方
log:对数
ln:自然对数
raise:toPower:乘方
exp:指数
数字处理
floor:向下取整
ceiling:向上取整
abs:绝对值
trunc:取整(直接截去小数)
位计算
bitwiseAnd:with:按位与
bitwiseOr:with:按位或
bitwiseXor:with:按位异或
leftshift:by:按位左移
rightshift:by:按位右移
onesComplement:按位取反
其他
uppercase:字符串大写
lowercase:字符串小写
canonical:
random随机数
randomn:随机数(小于传入的NSNumber)
now当前时间
noindex:
distanceToLocation:fromLocation:两坐标的距离
length:字符串的长度

    NSExpression *e1 = [NSExpression expressionForConstantValue:@"aaa"];
    id v1 = [e1 expressionValueWithObject:nil context:nil];
    NSExpression *e2 = [NSExpression expressionForConstantValue:@20];
    id v2 = [e2 expressionValueWithObject:nil context:nil];
    NSExpression *e3 = [NSExpression expressionForAggregate:@[e1, e2]];
    id v3 = [e3 expressionValueWithObject:nil context:nil];
    NSLog(@"%@ %@ %@", v1, v2, v3);
输出:
aaa 20 (
    aaa,
    20
)
    NSExpression *e1 = [NSExpression expressionForConstantValue:@[@10, @20]];
    id v1 = [e1 expressionValueWithObject:nil context:nil];
    NSExpression *e2 = [NSExpression expressionForConstantValue:@[@20, @30]];
    id v2 = [e2 expressionValueWithObject:nil context:nil];
    NSExpression *e3 = [NSExpression expressionForUnionSet:e1 with:e2];
    id v3 = [e3 expressionValueWithObject:nil context:nil];
    NSExpression *e4 = [NSExpression expressionForIntersectSet:e1 with:e2];
    id v4 = [e4 expressionValueWithObject:nil context:nil];
    NSLog(@"%@ %@", v1, v2);
    NSLog(@"%@ %@", v3, v4);
输出:
(
    10,
    20
) (
    20,
    30
)
{(
    30,
    10,
    20
)} {(
    20
)}
    NSExpression *r = [NSExpression expressionForFunction:[NSExpression expressionWithFormat:@"SELF"] 
              selectorName:@"function:withb:" 
              arguments:@[[NSExpression expressionForConstantValue:@"aa"], 
                          [NSExpression expressionForConstantValue:@"bb"]]];
    id rv = [r expressionValueWithObject:self context:nil];
    NSLog(@"%@", rv);

- (NSString *)function:(NSString *)a withb:(NSString *)b {
    NSLog(@"a= %@ b = %@", a, b);
    return [NSString stringWithFormat:@"%@%@", a, b];
}
输出:
a= aa b = bb
aabb

可见,arguments的值为function:withb:方法的两个入参的值,function:withb:的返回值为expressionValueWithObject的返回值,expressionValueWithObject的object需要传self表示对象self的function:withb:

    NSExpression *aaa = [NSExpression expressionForBlock:^id _Nonnull(id  _Nullable evaluatedObject, NSArray<NSExpression *> * _Nonnull expressions, NSMutableDictionary * _Nullable context) {
        NSLog(@"%@ %@ %@", evaluatedObject, expressions, context);
        return @"bbb";
    } arguments:@[[NSExpression expressionForConstantValue:@10]]];
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{@"key1":@"value1"}];
    id aaav = [aaa expressionValueWithObject:self context:dict];
    NSLog(@"%@", aaav);
输出:
<Predicate: 0x7ff5d5d2d7d0> (
    10
) {
    key1 = value1;
}
bbb

可见block的evaluatedObject为expressionValueWithObject传入的object,block的expressions为expressionForBlock传入的arguments,block的context为expressionValueWithObject传入的context,block的返回值为expressionValueWithObject的返回值

    NSPredicate *pp = [NSPredicate predicateWithFormat:@"SELF < 30"];
    NSExpression *bbb = [NSExpression expressionForConditional:pp
                         trueExpression:[NSExpression expressionForConstantValue:@10] 
                         falseExpression:[NSExpression expressionForConstantValue:@20]];
    id bbbv = [bbb expressionValueWithObject:@20 context:nil];
    NSLog(@"%@", bbbv);
输出:
10

因为20<30为真,所以bbb = trueExpression,即[NSExpression expressionForConstantValue:@10]

上一篇 下一篇

猜你喜欢

热点阅读