NSPredicate
一、简介
NSPredicate
指定数据被获取或者过滤的方式,是一个Foundation类。
Cocoa框架中的NSPredicate用于指定过滤器的条件(即查询),它的原理和用法都像SQL的WHERE
和正则表达式一样,作用相当于数据库的过滤器。
最常用到的函数:+ predicateWithFormat: 创建谓词串
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == 'Herbie'"];
//注意:如果谓词串中的文本块未被引用,则被看做是键路径,即需要用引号表明是字符串,单引号,双引号均可.键路径可以在后台包含许多强大的功能
二、谓词语法
范例数据源:
索引 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
名 | Alice | Bob | Charlie | Quentin |
姓 | Smith | Jones | Smith | Alberts |
年龄 | 24 | 27 | 33 | 31 |
背景:
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property NSNumber *age;
@end
NSArray *firstNames = @[ @"Alice", @"Bob", @"Charlie", @"Quentin" ];
NSArray *lastNames = @[ @"Smith", @"Jones", @"Smith", @"Alberts" ];
NSArray *ages = @[ @24, @27, @33, @31 ];
NSMutableArray *people = [NSMutableArray array];
[firstNames enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
Person *person = [[Person alloc] init];
person.firstName = firstNames[idx];
person.lastName = lastNames[idx];
person.age = ages[idx];
[people addObject:person];
}];
NSPredicate *bobPredicate = [NSPredicate predicateWithFormat:@"firstName = 'Bob'"];
NSPredicate *smithPredicate = [NSPredicate predicateWithFormat:@"lastName = %@", @"Smith"];
NSPredicate *thirtiesPredicate = [NSPredicate predicateWithFormat:@"age >= 30"];
// ["Bob Jones"]
NSLog(@"Bobs: %@", [people filteredArrayUsingPredicate:bobPredicate]);
// ["Alice Smith", "Charlie Smith"]
NSLog(@"Smiths: %@", [people filteredArrayUsingPredicate:smithPredicate]);
// ["Charlie Smith", "Quentin Alberts"]
NSLog(@"30's: %@", [people filteredArrayUsingPredicate:thirtiesPredicate]);
1.替换:
为了简便,多数不使用替换,而是直接输入 key path 、对象 和 $VARIABLE_NAME 。
%@
是对值为字符串,数字或者日期的对象的替换值。%K
是key path的替换值。$VARIABLE_NAME
是可以被NSPredicate -predicateWithSubstitutionVariables:
替换的值。
NSPredicate *ageIs33Predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"age", @33];
//为了简便,也写作:@"age = 33"
NSLog(@"Age 33: %@", [people filteredArrayUsingPredicate:ageIs33Predicate]);
//运行结果: ["Charlie Smith"]
NSPredicate *namesBeginningWithLetterPredicate = [NSPredicate predicateWithFormat:@"(firstName BEGINSWITH[cd] $letter) OR (lastName BEGINSWITH[cd] $letter)"];
//为了简便,也写作:@"(firstName BEGINSWITH[cd] 'A') OR (lastName BEGINSWITH[cd] 'A')"
NSLog(@"'A' Names: %@", [people filteredArrayUsingPredicate:[namesBeginningWithLetterPredicate predicateWithSubstitutionVariables:@{@"letter": @"A"}]]);
// 运行结果:["Alice Smith", "Quentin Alberts"]
2.基本比较:比较运算符
=
,==
:左右相等。>=
,=>
:大于或者等于。<=
,=<
:小于等于。>
<
!=
,<>
:不等于。BETWEEN
:左边的表达式等于右边的表达式的值或者介于它们之间。右边是一个有两个指定上限和下限的数值的数列(指定顺序的数列)。
比如,
1 BETWEEN { 0 , 33 }
,或者$INPUT BETWEEN { $LOWER, $UPPER }
。
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"number BETWEEN {1,5}"];
3.字符串比较
字符串比较在默认的情况下是区分大小写和音调的。在方括号中用关键字符c和d来修改操作,比如firstname BEGINSWITH[cd] $FIRST_NAME。
[c]不区分大小写 , [d]不区分发音符号即没有重音符号 , [cd]既不区分大小写,也不区分发音符号。
BEGINSWITH
:左边的表达式以右边的表达式作为开始。CONTAINS
:左边的表达式包含右边的表达式。ENDSWITH
:左边的表达式以右边的表达式作为结束。LIKE
:左边的表达式等于右边的表达式:?
和*
可作为通配符,其中?
匹配1个字符,*
匹配0个或者多个字符。MATCHES
:正则表达式:左边的表达式根据ICU v3(更多内容请查看ICU User Guide for Regular Expressions)的regex风格比较,等于右边的表达式。SELF :字符串本身,例:@"SELF == 'APPLE'"
//name 均是对象的属性 [NSPredicate predicateWithFormat:@"name CONTAINS[cd] 'xxx'"]; //包含某个(xxx)字符串 [NSPredicate predicateWithFormat:@"name BEGINSWITH[c] 'xxx'"]; //以某个字符串开头 [NSPredicate predicateWithFormat:@"name ENDSWITH[d] 'xxx'"]; //以某个字符串结束 [NSPredicate predicateWithFormat:@"name LIKE[cd] '*er*'"]; //*代表通配符,Like也接受[cd]. [NSPredicate predicateWithFormat:@"name LIKE[cd] '???er*'"]; NSString *regex = @"^A.+e$"; //以A开头,e结尾 [NSPredicate predicateWithFormat: @"name MATCHES %@",regex]; //在数组筛选中,如果我不想用任何实例方法,想筛选成员本身时,可以用self来代替 NSArray *array = @[@"jim", @"cook", @"jobs", @"APPLE"]; NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF == 'APPLE'"]; NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);
4.基本复合谓词
AND
,&&
:逻辑与
.OR
,||
:逻辑或
.NOT
,!
:逻辑非
.
5.合计操作
5.1关系操作
ANY
,SOME
:指定下列表达式中的任意元素。比如,ANY children.age < 18
。ALL
:指定下列表达式中的所有元素。比如,ALL children.age < 18
。NONE
:指定下列表达式中没有的元素。比如,NONE children.age < 18
。它在逻辑上等于NOT (ANY ...)
。IN
:等于SQL的IN
操作,左边的表达必须出现在右边指定的集合中。比如,name IN { 'Ben', 'Melissa', 'Nick' }
。
5.2数组操作
array[index]
:指定数组
中特定索引处的元素。array[FIRST]
:指定数组
中的第一个元素。array[LAST]
:指定数组
中的最后一个元素。array[SIZE]
:指定数组
的大小。
5.3布尔值谓词
TRUEPREDICATE
:结果始终为真
的谓词。FALSEPREDICATE
:结果始终为假
的谓词。
三、应用场景
1.集合中使用NSPredicate
Foundation提供使用谓词(predicate)来过滤NSArray
/NSMutableArray
&NSSet
/NSMutableSet
的方法。
对不可变的集合(NSArray
&NSSet)
,通过评估接收到的predicate,用 `filteredArrayUsingPredicate:` 或
`filteredSetUsingPredicate:` 方法来返回一个不可变集合:
filteredArrayUsingPredicate: 是NSArray数组的一种类别方法,循环过滤数组中的内容,将值为YES的对象累积到结果数组中返回。
//对NSArray进行过滤 NSArray *array = [[NSArray alloc]initWithObjects:@"beijing",@"shanghai",@"guangzou",@"wuhan", nil]; NSString *string = @"ang"; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@",string]; NSLog(@"%@",[array filteredArrayUsingPredicate:pred]);
对可变集合(NSMutableArray
&NSMutableSet
),可以使用方法filterUsingPredicate:
,它可以通过运行接收到的谓词来移除评估结果为FALSE
的对象。
NSDictionary
可以用谓词来过滤它的键和值(两者都为NSArray
对象)。NSOrderedSet
可以由过滤的NSArray
或NSSet
生成一个新的有序的集,或者NSMutableSet
可以简单的removeObjectsInArray:
,来传递通过_否定_predicate过滤的对象。
注意在筛选过程中,要灵活利用成员实例方法,如:
lenght、
integerValue
NSArray *array = @[@"jim", @"cook", @"jobs", @"sdevm"]; NSPredicate *pre = [NSPredicate predicateWithFormat:@"length > 3"];//lenght就是对数组成员执行[xxxx lenght]然后判断返回的NSUInteger值是否大于3 NSLog(@"%@", [array filteredArrayUsingPredicate:pre]); //结果:( cook, jobs, sdevm ) //扩展到NSString其他方法又比如integerValue: NSArray *array = @[@"2", @"3", @"4", @"5"]; NSPredicate *pre = [NSPredicate predicateWithFormat:@"integerValue >= %@", @3]; NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);
如果我不想用任何实例方法,想筛选成员本身应该怎么做呢?这时候就可以用
self
来代替:
NSArray *array = @[@"2", @"3", @"4", @"5"]; NSPredicate *pre = [NSPredicate predicateWithFormat:@"self CONTAINS %@", @3]; NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);
2.模型中使用NSPredicate
--- 由集合拓展到模型
由`利用成员实例方法(集合中成员的方法)`拓展到`利用成员方法(集合中对象的属性的方法)`
筛选出数组成员方法[people firstName](firstName
属性的get方法)返回值 = 'Bob' 的成员。
NSPredicate *bobPredicate = [NSPredicate predicateWithFormat:@"firstName = 'Bob'"]; // ["Bob Jones"] NSLog(@"Bobs: %@", [people filteredArrayUsingPredicate:bobPredicate]);
3.多重筛选NSCompoundPredicate
如果需要匹配数个属性的筛选,用AND
或者OR
来串联显然有点麻烦。
NSCompoundPredicate
类可以满足我们的需求,它可以将多个NSPredicate
对象的组合,组合方式可以是AND
或者OR
andPredicateWithSubpredicates: orPredicateWithSubpredicates:
NSPredicate *pre1 = [NSPredicate predicateWithFormat:@"code >= %@", @3]; NSPredicate *pre2 = [NSPredicate predicateWithFormat:@"code <= %@", @2]; //以AND形式组合 NSPredicate *pre = [NSCompoundPredicate andPredicateWithSubpredicates:@[pre1,pre2]]; //以OR形式组合 NSPredicate *pre = [NSCompoundPredicate orPredicateWithSubpredicates:@[pre1, pre2]];
4.匹配用法evaluateWithObject:
其实NSPredicate不仅可以用于筛选,还可以用来判断匹配直接返回是否符合。
主要方法是 -(BOOL)evaluateWithObject:(id)object;
Test *test1 = [[Test alloc]init];
test1.name = @"absr";
test1.code = @1;
NSPredicate *pres = [NSPredicate predicateWithFormat:@"code == %@", @2];
BOOL match = [pres evaluateWithObject:test1];
当然最常用的还是配合配合正则表达式,列举几个常用的正则:
- 是否以a开头以e结尾
NSString *string=@"assdbfe";
NSString *targetString=@"^a.+e$";
NSPredicate *pres = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", targetString];
BOOL match = [pres evaluateWithObject:string];
- 是否是邮箱
NSString *strRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{1,5}";
- 是否是手机号
NSString *strRegex = @"[0-9]{1,20}";
5.Core Data中使用NSPredicate
NSFetchRequest
有一个predicate
属性,它可以指定管理对象应该被获取的逻辑条件。谓词的使用规则在这里同样适用,唯一的区别在于,在管理对象环境中,谓词由持久化存储助理(persistent store coordinator)评估,而不像集合那样在内存中被过滤。
//查询 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName]; //条件查询 NSPredicate *predicate = [NSPredicate predicateWithFormat:@""]; request.predicate = predicate; //执行查询 NSArray *objectArray = [self.managedObjectContext executeFetchRequest:request error:nil]; if (![objectArray count]) { NSLog(@"未找到符合条件的对象!"); } return objectArray;
四、Block谓词 --- 另一种创建NSPredicate的方式
最后,如果你实在不愿意学习NSPredicate
的格式语法,你也可以学学NSPredicate +predicateWithBlock:
。
NSPredicate *shortNamePredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [[evaluatedObject firstName] length] <= 5;
}];
// ["Alice Smith", "Bob Jones"]
NSLog(@"Short Names: %@", [people filteredArrayUsingPredicate:shortNamePredicate]);
...好吧,虽然使用predicateWithBlock:
是懒人的做法,但它也并不是一无是处。
事实上,因为block可以封装任意的计算,所以有一个查询类是无法以NSPredicate
格式字符串形式来表达的(比如对运行时被动态计算的值的评估)。而且当同一件事情可以用NSExpression
结合自定义选择器来完成时,block为完成工作提供了一个方便的接口。
重要提示:由predicateWithBlock:
生成的NSPredicate
不能用于由SQLite
存储库支持的Core Data数据的提取要求。
本文参考自NSHipster.cn、bawn。
posted on 2016-03-25 15:40 Wilson_CYS 阅读(633) 评论(0) 编辑 收藏 举报