前言
首先,我们需要知道何谓谓词,让我们看看官方的解释:
The NSPredicate class is used to define logical conditions used to constrain a search either for a fetch or for in-memory filtering.
NSPredicate类是用来定义逻辑条件约束的获取或内存中的过滤搜索。
可以使用谓词来表示逻辑条件,用于描述对象持久性存储在内存中的对象过滤。其实意思就是:我是一个过滤器,不符合条件的都滚开。
一、NSPredicate的基本语法
我们使用一门语言,无论是外语还是计算机语言,总是从语法开始的,这样我们才能正确的把握逻辑。所以我们从语法开始说起。在这部分我们仅关心其语法的使用
只要我们使用谓词(NSPredicate)都需要为谓词定义谓词表达式,而这个表达式必须是一个返回BOOL的值。
谓词表达式由表达式、运算符和值构成。
1.比较运算符
比较运算符如下
=、==:判断两个表达式是否相等,在谓词中=和==是相同的意思都是判断,而没有赋值这一说
NSNumber *testNumber = @123; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF = 123"]; if ([predicate evaluateWithObject:testNumber]) { NSLog(@"testString:%@", testNumber); }
我们可以看到输出的内容为:
2016-01-07 11:12:27.281 PredicteDemo[4130:80412] testString:123
NSNumber *testNumber = @123;NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BETWEEN {100, 200}"]; if ([predicate evaluateWithObject:testNumber]) { NSLog(@"testString:%@", testNumber); } else { NSLog(@"不符合条件"); }
输出结果为:
2016-01-07 11:20:39.921 PredicteDemo[4366:85408] testString:123
2.逻辑运算符
AND、&&:逻辑与,要求两个表达式的值都为YES时,结果才为YES。
NSArray *testArray = @[@1, @2, @3, @4, @5, @6]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF > 2 && SELF < 5"]; NSArray *filterArray = [testArray filteredArrayUsingPredicate:predicate]; NSLog(@"filterArray:%@", filterArray);
输出结果为:
2016-01-07 11:27:01.885 PredicteDemo[4531:89537] filterArray:(
3,
4
)
3.字符串比较运算符
注:字符串比较都是区分大小写和重音符号的。如:café和cafe是不一样的,Cafe和cafe也是不一样的。如果希望字符串比较运算不区分大小写和重音符号,请在这些运算符后使用[c],[d]选项。其中[c]是不区分大小写,[d]是不区分重音符号,其写在字符串比较运算符之后,比如:name LIKE[cd] 'cafe',那么不论name是cafe、Cafe还是café上面的表达式都会返回YES。
4.集合运算符
NSArray *filterArray = @[@"ab", @"abc"]; NSArray *array = @[@"a", @"ab", @"abc", @"abcd"]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", filterArray]; NSLog(@"%@", [array filteredArrayUsingPredicate:predicate]);
代码的作用是将array中和filterArray中相同的元素去除,输出为:
2016-01-07 13:17:43.669 PredicteDemo[6701:136206] (
a,
abcd
)
5.直接量
在谓词表达式中可以使用如下直接量
6.保留字
下列单词都是保留字(不论大小写)
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、CAST、TRUEPREDICATE、FALSEPREDICATE
注:虽然大小写都可以,但是更推荐使用大写来表示这些保留字
二、谓词的用法
1.定义谓词
一般我们使用下列方法来定义一个谓词
NSPredicate *predicate = [NSPredicate predicateWithFormat:<#(nonnull NSString *), ...#>];
下面我们通过几个简单的例子来看看它该如何使用:
首先我们需要定义一个模型,因为示例中需要用到它
ZLPersonModel.h
#import <Foundation/Foundation.h>typedef NS_ENUM(NSInteger, ZLPersonSex) { ZLPersonSexMale = 0, ZLPersonSexFamale};@interface ZLPersonModel : NSObject/** NSString 姓名 */@property (nonatomic, copy) NSString *name;/** NSUInteger 年龄 */@property (nonatomic, assign, readonly) NSUInteger age;/** ZLPersonSex 性别 */@property (nonatomic, assign, readonly) ZLPersonSex sex;+ (instancetype)personWithName:(NSString *)name age:(NSUInteger)age sex:(ZLPersonSex)sex;@end
ZLPersonModel.m
#import "ZLPersonModel.h"@implementation ZLPersonModel- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(ZLPersonSex)sex{ if (self = [super init]) { _name = name; _age = age; _sex = sex; } return self;}+ (instancetype)personWithName:(NSString *)name age:(NSUInteger)age sex:(ZLPersonSex)sex{ return [[self alloc] initWithName:name age:age sex:sex];}- (NSString *)description{ return [NSString stringWithFormat:@"[name = %@, age = %ld, sex = %ld]", self.name, self.age, self.sex];}@end
下面让我们进入正题
例一:(最简单的使用)
ZLPersonModel *sunnyzl = [ZLPersonModel personWithName:@"sunnyzl" age:29 sex:ZLPersonSexMale]; ZLPersonModel *jack = [ZLPersonModel personWithName:@"jack" age:22 sex:ZLPersonSexMale]; // 首先我们来看一些简单的使用 // 1.判断姓名是否是以s开头的 NSPredicate *pred1 = [NSPredicate predicateWithFormat:@"name LIKE 's*'"]; // 输出为:sunnyzl:1, jack:0 NSLog(@"sunnyzl:%d, jack:%d", [pred1 evaluateWithObject:sunnyzl], [pred1 evaluateWithObject:jack]); // 2.判断年龄是否大于25 NSPredicate *pred2 = [NSPredicate predicateWithFormat:@"age > 25"]; // 输出为:sunnyzl的年龄是否大于25:1, jack的年龄是否大于25:0 NSLog(@"sunnyzl的年龄是否大于25:%d, jack的年龄是否大于25:%d", [pred2 evaluateWithObject:sunnyzl], [pred2 evaluateWithObject:jack]);
看到这里我们会发现evaluateWithObject:方法返回的是一个BOOL值,如果符合条件就返回YES,不符合就返回NO。而即使是最简单的使用也有一些大用处,比如以前我们写判断手机号码、邮编等等,像我就喜欢用John Engelhart大神的RegexKitLite,然而由于年代久远需要导入libicucore.dylib库(xcode7为libicucore.tbd)且由于是mrc又需要添加-fno-objc-arc,至此我们才能使用。然而使用谓词让我们可以用同样简洁的代码实现相同的功能
例二:
(判断手机号是否正确)
- (BOOL)checkPhoneNumber:(NSString *)phoneNumber{ NSString *regex = @"^[1][3-8]//d{9}$"; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; return [pred evaluateWithObject:phoneNumber];}
例三:检测字符串中是否有特殊字符
- (BOOL)checkSpecialCharacter:(NSString *)string{ NSString *regex = @"[`~!@#$^&*()=|{}':;',//[//].<>/?~!@#¥……&*()――|{}【】‘;:”“'。,、?]+"; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; return [pred evaluateWithObject:string];}
2.使用谓词过滤集合
此部分是我们需要掌握的重点,因为从这里我们就可以看到谓词的真正的强大之处
其实谓词本身就代表了一个逻辑条件,计算谓词之后返回的结果永远为BOOL类型的值。而谓词最常用的功能就是对集合进行过滤。当程序使用谓词对集合元素进行过滤时,程序会自动遍历其元素,并根据集合元素来计算谓词的值,当这个集合中的元素计算谓词并返回YES时,这个元素才会被保留下来。请注意程序会自动遍历其元素,它会将自动遍历过之后返回为YES的值重新组合成一个集合返回。
其实类似于我们使用tableView设置索引时使用的下段代码
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView{ return [self.cityGroup valueForKey:@"title"];}
中的[self.cityGroup valueForKey:@"title"]。它的作用是遍历所有title并将得到的值组成新的数组。
- (NSArray<ObjectType> *)filteredArrayUsingPredicate:(NSPredicate *)predicate
:使用指定的谓词过滤NSArray集合,返回符合条件的元素组成的新集合- (void)filterUsingPredicate:(NSPredicate *)predicate
:使用指定的谓词过滤NSMutableArray,剔除集合中不符合条件的元素- (NSSet<ObjectType> *)filteredSetUsingPredicate:(NSPredicate *)predicate NS_AVAILABLE(10_5, 3_0)
:作用同NSArray中的方法- (void)filterUsingPredicate:(NSPredicate *)predicate NS_AVAILABLE(10_5, 3_0)
:作用同NSMutableArray中的方法。下面让我们来看几个例子:
例一:
NSMutableArray *arrayM = [@[@20, @40, @50, @30, @60, @70] mutableCopy]; // 过滤大于50的值 NSPredicate *pred1 = [NSPredicate predicateWithFormat:@"SELF > 50"]; [arrayM filterUsingPredicate:pred1]; NSLog(@"arrayM:%@", arrayM); NSArray *array = @[[ZLPersonModel personWithName:@"Jack" age:20 sex:ZLPersonSexMale], [ZLPersonModel personWithName:@"Rose" age:22 sex:ZLPersonSexFamale], [ZLPersonModel personWithName:@"Jackson" age:30 sex:ZLPersonSexMale], [ZLPersonModel personWithName:@"Johnson" age:35 sex:ZLPersonSexMale]]; // 要求取出包含‘son'的元素 NSPredicate *pred2 = [NSPredicate predicateWithFormat:@"name CONTAINS 'son'"]; NSArray *newArray = [array filteredArrayUsingPredicate:pred2]; NSLog(@"%@", newArray);
输出为
2016-01-07 16:50:09.510 PredicteDemo[13660:293822] arrayM:(
60,
70
)
2016-01-07 16:50:09.511 PredicteDemo[13660:293822] (
"[name = Jackson, age = 30, sex = 0]",
"[name = Johnson, age = 35, sex = 0]"
)
从这个例子我们就可以看到NSPredicate有多么强大,如果让我们用其他的方法来实现又是一大堆if...else。
让我们来回顾一下上面的从第二个数组中去除第一个数组中相同的元素
例二:
NSArray *filterArray = @[@"ab", @"abc"]; NSArray *array = @[@"a", @"ab", @"abc", @"abcd"]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", filterArray]; NSLog(@"%@", [array filteredArrayUsingPredicate:predicate]);
输出为:
2016-01-07 13:17:43.669 PredicteDemo[6701:136206] (
a,
abcd
)
如果我们不用NSPredicate的话,肯定又是各种if...else,for循环等等。可以看出NSPredicate的出现为我们节省了大量的时间和精力。
3.在谓词中使用占位符参数
我们上面所有的例子中谓词总是固定的,然而我们在现实中处理变量时决定了谓词应该是可变的。下面我们来看看如果让谓词变化起来。
首先如果我们想在谓词表达式中使用变量,那么我们需要了解下列两种占位符
其实相当于变量名与变量值
除此之外,还可以在谓词表达式中使用动态改变的属性值,就像环境变量一样
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF CONTAINS $VALUE"];
上述表达式中,开头,随着程序改变$VALUE这个谓词表达式的比较条件就可以动态改变。
下面我们通过一个例子来看看这三个重要的占位符应该如何使用
例一:
NSArray *array = @[[ZLPersonModel personWithName:@"Jack" age:20 sex:ZLPersonSexMale], [ZLPersonModel personWithName:@"Rose" age:22 sex:ZLPersonSexFamale], [ZLPersonModel personWithName:@"Jackson" age:30 sex:ZLPersonSexMale], [ZLPersonModel personWithName:@"Johnson" age:35 sex:ZLPersonSexMale]]; // 定义一个property来存放属性名,定义一个value来存放值 NSString *property = @"name"; NSString *value = @"Jack"; // 该谓词的作用是如果元素中property属性含有值value时就取出放入新的数组内,这里是name包含Jack NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K CONTAINS %@", property, value]; NSArray *newArray = [array filteredArrayUsingPredicate:pred]; NSLog(@"newArray:%@", newArray); // 创建谓词,属性名改为age,要求这个age包含$VALUE字符串 NSPredicate *predTemp = [NSPredicate predicateWithFormat:@"%K > $VALUE", @"age"]; // 指定$VALUE的值为 25 NSPredicate *pred1 = [predTemp predicateWithSubstitutionVariables:@{@"VALUE" : @25}]; NSArray *newArray1 = [array filteredArrayUsingPredicate:pred1]; NSLog(@"newArray1:%@", newArray1); // 修改 $VALUE的值为32 NSPredicate *pred2 = [predTemp predicateWithSubstitutionVariables:@{@"VALUE" : @32}]; NSArray *newArray2 = [array filteredArrayUsingPredicate:pred2]; NSLog(@"newArray2:%@", newArray2);
输出为
2016-01-07 17:28:02.062 PredicteDemo[14542:309494] newArray:(
"[name = Jack, age = 20, sex = 0]",
"[name = Jackson, age = 30, sex = 0]"
)
2016-01-07 17:28:02.063 PredicteDemo[14542:309494] newArray1:(
"[name = Jackson, age = 30, sex = 0]",
"[name = Johnson, age = 35, sex = 0]"
)
2016-01-07 17:28:02.063 PredicteDemo[14542:309494] newArray2:(
"[name = Johnson, age = 35, sex = 0]"
)
从上例中我们主要可以看出来%K和$VALUE的含义。
那么至此NSPredicate就到到此介绍完毕。
因为本人水平有限,如果有什么好的建议请联系我。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对武林网的支持。
新闻热点
疑难解答