NSPredicate
NSPredicate
任何Cocoa类对象都可以支持谓词,但是此类需要实现键值编码(key-value-coding)协议。
一、创建谓词对象有3种方式:
1. 通过格式化字符串创建谓词;
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat argumentArray:(nullable NSArray *)arguments;
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat arguments:(va_list)argList;
+ (NSPredicate*)predicateWithBlock:(BOOL (^)(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings))block;
- (instancetype)predicateWithSubstitutionVariables:(NSDictionary<NSString *, id> *)variables;
NSString *attributeName = @"firstName";
NSString *attributeValue = @"Adam";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K LIKE %@",
attributeName, attributeValue];
格式:firstName like "Adam".
2. 直接通过代码创建谓词
NSExpression
NSComparisonPredicate
NSCompoundPredicate
相对格式化字符串创建,代码量较多。一般不建议。
- 比较类型:NSComparisonPredicate
//创建左侧表达式对象 对应为键
NSExpression * left = [NSExpression expressionForKeyPath:@"length"];
//创建右侧表达式对象 对应为值
NSExpression * right = [NSExpression expressionForConstantValue:@4]];
//创建比较谓词对象 这里设置为严格等于
NSComparisonPredicate * pre = [NSComparisonPredicate predicateWithLeftExpression:left rightExpression:right modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:NSCaseInsensitivePredicateOption];
NSArray * array = @[@"001",@"123",@"4323",@"123456",@"54321"];
NSArray * result = [array filteredArrayUsingPredicate:pre];
NSLog(@"%@",result);
//打印@[@"4323"]
- 复核:NSCompoundPredicate
3.通过模板创建谓词。
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"length = $LENGTH"];
predicate = [predicate predicateWithSubstitutionVariables:@{@"LENGTH":@5}];
NSArray * test = @[@"333",@"22",@"123",@"12345",@"543321"];
NSArray * result = [test filteredArrayUsingPredicate:predicate];
NSLog(@"%@",result);
//打印@[@"12345"]
在进行%@格式化时,如果使用的是变量则不需要添加引号,解析器会帮助你添加,如果使用到常量,则要用转义字符进行转义.
对于属性名,如果也需要进行格式化,需要注意不能使用%@,这个符号在解析时会被解析器自动添加上引号,可以使用%K,
二、运算符
比较运算符
=(==)、>、>=(=>)、<、<=(=<)、!=(<>)、BETWEEN
BETWEEN
$INPUT BETWEEN { $LOWER, $UPPER }
[NSPredicate predicateWithFormat: @"attributeName BETWEEN %@", @[@1, @10]];
关于Null
如果想要匹配空值,除了其他比较之外,还必须包括一个特定的测试,如下面的片段所示。
predicate = [NSPredicate predicateWithFormat:@"(firstName == %@) || (firstName = nil)", firstName];
filteredArray = [array filteredArrayUsingPredicate:predicate];
逻辑运算符
AND、&&、OR、||、NOT、!
TRUEPREDICATE 、FALSEPREDICATE
字符串比较运算符([c]忽略大小写[d]忽略重音符号[cd]忽略大小写和重音符号)
BEGINSWITH:检查字符串是否以指定的字符串开头
SELF BEGINSWITH “a”
SELF BEGINSWITH[cd] “café”
ENDSWITH:检查字符串是否以指定的字符串结尾
CONTAINS:检查字符串是否包含指定的字符串
LIKE:检查字符串是否匹配指定字符串模板
? 占1个字符,*占0或任意个字符。
SELF LIKE ‘ab’ (包含)
SELF LIKE ‘?ab’ (第2、3个字符为ab)
MATCHES:检查字串串是否匹配指定的正则表达式(正则表达式的执行效率最低,但功能强大,最为常用)
SELF MATCHES
集合运算符
ANY、SOME:任意一个元素满足条件,就返回YES
ALL:所有元素都满足条件,返回YES
NONE:没有任何元素满足条件返回YES
IN:等价SQL中的IN运算符,当左边表达式或值出现在右边,返回YES
self in ,not self in
数组过滤掉另外一个数组的所有数据
NSPredicate *predicate = [NSPredicate predicateWithFormat:@“NOT(SELF IN %@)”,array];
[source filteredArrayUsingPredicate:predicate];
array[index]:返回array数组中index索引处的元素
array[FIRST]:返回array数组中第一个元素
array[LAST]:返回array数组中最后一个元素
array[SIZE]:返回array数组中元素的个数
键值编码方式NSKeyValueCoding
@avg 均值 employees.@avg.age > 20
@sum 求和 employees.@sum.age > 100
@max 最大值 employees.@max.age > 50
@min 最小值 employees.@min.age > 20
@count 数量 employees.@count > 20
可直接使用valueForKeyPath:获取结果。
如:[company valueForKeyPath:@"employees.@avg.age"]
@distinctUnionOfArrays、@distinctUnionOfObjects、@unionOfArrays、@unionOfObjects
配合valueForKeyPath:使用
@distinctUnionOfObjects、@unionOfObjects
返回一个数组,这个数组是由操作符.右侧属性的值组成的,并且重复的值被过滤掉(嵌套的数组中不去重)。@unionOfObjects逻辑和@distinctUnionOfObjects相同,但是重复的值没有被过滤掉。
@distinctUnionOfArrays、@unionOfArrays
用于嵌套数组。
返回一个数组,但是将数组中的.右侧属性的值拆分到一个数组里面,不包括重复值。@unionOfArrays包括重复值。
SUBQUERY
@"SUBQUERY(employees, $employee,$employee.age >50).@count==employees[SIZE]"
标识符
C风格的标识符
任何C风格的标识符均不是保留字。
#符号
用于将保留字转义为用户标识符。
[\]{octaldigit}{3}
用于转义一个八进制数字(\后跟3个八进制数字)。
[\][xX]{hexdigit}{2}
用于转义十六进制数字(\x或\x后面跟着2个十六进制数字)。
[\][uU]{hexdigit}{4}
用于转义Unicode数字(\u或\u后跟4个十六进制数字)。
其他
一般来说,连接(跨关系的查询)也是开销很大的操作,如果可以的话,应该避免它们。在测试一对一关系时,如果已经拥有或可以轻松检索关系源对象(或其对象 ID),则测试对象相等性比测试源对象的属性更有效。而不是编写以下内容:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"department.name like %@", [department name]];
更高效的方式如下:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"department == %@", department];
在进行多条件查询时候,则通常将其结构化以避免连接也会更有效。
@"firstName beginswith[cd] 'Matt' AND (ANY directreports.paygrade <= 7)"
@"(ANY directreports.paygrade <= 7) AND (firstName beginswith[cd] 'Matt')"
因为前者避免进行连接,除非第一次测试成功。
保留字
AND, OR, IN, NOT, ALL, ANY, SOME, NONE, LIKE, CASEINSENSITIVE, CI, MATCHES, CONTAINS, BEGINSWITH, ENDSWITH, BETWEEN, NULL, NIL, SELF, TRUE, YES, FALSE, NO, FIRST, LAST, SIZE, ANYKEY, SUBQUERY, FETCH, CAST, TRUEPREDICATE, FALSEPREDICATE, UTI-CONFORMS-TO, UTI-EQUALS
语法说明
| 语法 | 含义 | 备注 |
|---|---|---|
=、== |
左侧等于右侧 | grade == "7" |
>=、=> |
左侧大于等于右侧 | |
<=、=< |
左侧小于等于右侧 | |
> |
左侧大于右侧 | |
< |
左侧小于右侧 | |
!=、<> |
左侧不等于右侧 | |
BETWEEN |
左侧在右侧的集合中 key BETWEEN @[,@2] | |
TRUEPREDICATE |
总是返回YES的谓词 | |
FALSEPREDICATE |
总是返回NO的谓词 | |
AND、&& |
逻辑与 | |
OR、` |
` | |
NOT、! |
逻辑非 | |
BEGINWITH |
左侧以右侧字符串开头 | |
ENDWITH |
左侧以右侧字符串结尾 | |
CONTAINS |
左侧字符串含右侧字符串,cd不区分大小写和变音符号 |
name CONTAINS[cd] "stein" |
LIKE |
左侧等于右侧,并且*和?等通配符可以使用。*代表任意个,?代表一个字符 |
firstName LIKE "Juan" |
MATCHES |
正则匹配 | |
ALL |
对于数组集合类,验证其中所有元素 | ALL children.age > 12 |
ANY、SOME |
对于数组集合类,验证其中任一元素 | ANY children.age > 12 |
NONE |
作用等同于NOT (ANY) |
|
IN |
左侧在右侧集合中 | |
SELF |
被验证的对象本身 |