为什么要使用NSPredicate?
在做应用实现的过程中,经常会遇到一些筛选符合条件数据的需求,对于普通人来说,设计出一个筛选速度很快的算法并不是一件容易的事.所以iOS内部将这些实现进行了封装,便于友好地支持开发者的使用,降低使用的难度,加快开发的进程.
NSPredicate的使用场景
NSPredicate的使用多数是通过使用不同的谓词来实现,通过常用的谓词来介绍在开发场景中的使用.例如:
Match
NSPredicate的第一个强大的功能就是直接用于类型的匹配,使用起来跟正则表达式类似,用于匹配到符合条件的元素
- 匹配全是中文的字符串
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"^[\\u4e00-\\u9fa5]+$"];
for (NSString * ele in array) {
NSLog(@"[%@]中%@都是中文字符", ele, [predicate evaluateWithObject:ele] ? @"全部" : @"非全部");
}
- 匹配字符串中是否包含中文
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @".*[\\u4e00-\\u9fa5]+.*"];
for (NSString * ele in array) {
NSLog(@"[%@]中%@中文字符", ele, [predicate evaluateWithObject:ele] ? @"包含" : @"不包含");
}
Contains
contains主要用于筛选匹配包含指定字串的字符串。例如:
- 匹配字符串中是否包含指定字串
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@", @"China"];
for (NSString * ele in array) {
NSLog(@"[%@]中%@[China]", ele, [predicate evaluateWithObject:ele] ? @"包含" : @"不包含");
}
- 匹配字符串中是否包含指定的子串(忽略大小写)
如果需要忽略大小写可以使用[c]来做筛选选项.多数情况下会与[d]一起使用,该筛选项表示忽略重音符号.
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[c] %@", @"China"];
for (NSString * ele in array) {
NSLog(@"[%@]中%@[China]", ele, [predicate evaluateWithObject:ele] ? @"包含" : @"不包含");
}
BeginsWith && EndsWith
主要用于筛选以指定子串开头/结尾的字符串.例如:
- 筛选以China开头的字符串(不区分大小写)
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH[c] %@", @"China"];
for (NSString * ele in array) {
NSLog(@"[%@]%@以%@开头", ele, [predicate evaluateWithObject:ele] ? @"是" : @"不是", @"China");
}
- 筛选以China结尾的字符串(不区分大小写)
NSArray <NSString *> *array = @[@"ABC", @"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF ENDSWITH[c] %@", @"China"];
for (NSString * ele in array) {
NSLog(@"[%@]%@以%@结尾", ele, [predicate evaluateWithObject:ele] ? @"是" : @"不是", @"China");
}
Like
主要用于筛选具备某一类相似特征的字符串,通常使用*作为通配符.例如:
- 筛选以.png结尾的资源名称
NSArray <NSString *> *array = @[@"loading_001.png", @"loading_002.png", @"loading_003.png",@"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF LIKE %@", @"loading_*.png"];
for (NSString * ele in array) {
NSLog(@"[%@]%@形如[loading_*.png]条件", ele, [predicate evaluateWithObject:ele] ? @"符合" : @"不符合");
}
In
主要用于在集合中筛选出共同部分,例如:
- 在数组array1中帅选出与数组array2相同的元素:
NSArray <NSString *> *array1 = @[@"one", @"two", @"three", @"four"];
NSArray <NSString *> *array2 = @[@"three", @"four", @"five"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF IN %@", array2];
NSArray<NSString *> *commonElements = [array1 filteredArrayUsingPredicate:predicate];
NSLog(@"commonElements == %@", commonElements);
- 筛选出set1中与set2中相同的元素:
NSSet<NSString *> *set1 = [NSSet setWithObjects:@"one", @"two", @"three", @"four", nil];
NSSet<NSString *> *set2 = [NSSet setWithObjects:@"three", @"four", @"five", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF IN %@", set2];
NSSet<NSString *> *commonElements = [set1 filteredSetUsingPredicate:predicate];
NSLog(@"commonElements == %@", commonElements);
Not
主要用于相反选择,用于筛选出不符合指定条件的元素.例如:
- 筛选出array1与array2不相同的元素:
NSSet<NSString *> *set1 = [NSSet setWithObjects:@"one", @"two", @"three", @"four", nil];
NSSet<NSString *> *set2 = [NSSet setWithObjects:@"three", @"four", @"five", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", set2];
NSSet<NSString *> *commonElements = [set1 filteredSetUsingPredicate:predicate];
NSLog(@"commonElements == %@", commonElements);
- 筛选出数组中不符合like规则的元素:
NSArray <NSString *> *array = @[@"loading_001.png", @"loading_002.png", @"loading_003.png",@"我是一个老男孩", @"China,加油!", @"I like china"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF LIKE %@)", @"loading_*.png"];
for (NSString * ele in array) {
NSLog(@"[%@]%@形如[loading_*.png]条件", ele, [predicate evaluateWithObject:ele] ? @"不符合" : @"符合");
}
逻辑运算符号
还可以使用诸如==, >, <, >=, <=, 以及AND, OR等逻辑运算符号进行条件筛选.
为了方便说明,定一个Student类:
@interface Student : NSObject
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) CGFloat score;
- (instancetype)initWithName: (NSString *)name score: (CGFloat)score;
@end
@implementation Student
- (instancetype)initWithName: (NSString *)name score: (CGFloat)score {
self = [super init];
if (self) {
self.name = name;
self.score = score;
}
return self;
}
@end
并创建students数组
NSArray<Student *> *students = @[
[[Student alloc] initWithName:@"Frank" score:77],
[[Student alloc] initWithName:@"Dong" score:99],
[[Student alloc] initWithName:@"Ping" score:88],
[[Student alloc] initWithName:@"Chao" score:80],
];
- 筛选出name="Dong"的同学:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name == %@ ", @"Dong"];
NSArray<Student *> *result = [students filteredArrayUsingPredicate:predicate];
NSLog(@"result == %@, name == %@", result, result.firstObject.name);
**使用属性进行筛选时,可以省略SELF,直接使用属性名进行筛选,简化书写。**例如筛选成绩小于60,大于90的同学时可以直接使用:
"score < 60 OR score >90 "
- 筛选出成绩大于80且小于90的同学:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"score >= 80 and score <= 90"];
NSArray<Student *> *result = [students filteredArrayUsingPredicate:predicate];
for (Student *stu in result) {
NSLog(@"name == %@, score == %lf", stu.name, stu.score);
}
Attention:
需要注意的一点是,当属性名作为参数传入匹配范型的时候,不能使用%@进行参数格式限定,而应该使用%K进行格式限定。因为在默认的情况下,使用%@时,系统会给参数添加引号,例如
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@ ", @"Dong"];
编译之后会变成形如:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == 'Dong' "];
而不是:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"'name' == 'Dong' "];
所以当参数名需要使用参数进行传递时,需要使用
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@ ", @"name", @"Dong"];
而不是:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ == %@ ", @"name", @"Dong"];