謂詞: 簡單的說就是一個過濾器, 符合條件的留下, 不符合條件的刪除
一. NSPredicate的基本語法
只要使用謂詞(NSPredicate)都需要為謂詞定義謂詞表達(dá)式, 而這個表達(dá)式必須是一個返回BOOL的值
謂詞表達(dá)式由表達(dá)式, 運(yùn)算符和值構(gòu)成
1: 比較運(yùn)算符
(1)=、==:判斷兩個表達(dá)式是否相同
備注: 在謂詞中=和==是都是相同的意思, 不是賦值
(2)>=, =>: 判斷左邊的表達(dá)式的值是否 大于或等于 右邊表達(dá)式的值
(3)<=, =<: 判斷左邊的表達(dá)式的值是否 小于或等于 右邊表達(dá)式的值
(4)>: 判斷左邊表達(dá)式的值是否 大于 右邊表達(dá)式的值
(5)<: 判斷左邊表達(dá)式的值是否 小于 右邊表達(dá)式的值
(6)!=, <>: 判斷兩個表達(dá)式是否 不相等
(7)BETWEEN: 該表達(dá)式必須滿足: 表達(dá)式 BETWEEN {下限,上限} 的格式, 要求該表達(dá)式必須 大于或等于下限, 并小于等于上限
例:
NSNumber *testNumber = @16;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BETWEEN {12,19}"];
if ([predicate evaluateWithObject:testNumber]) {
NSLog(@"testNumber = %@", testNumber);
}
else {
NSLog(@"不符合");
}
2: 邏輯運(yùn)算符:
(1)AND, &&: 邏輯與, 要求兩個表達(dá)式的值都為YES時, 結(jié)果才為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);
輸出結(jié)果:filterArray: (
3,
4
)
(2)OR, ||: 邏輯或, 要求其中一個表達(dá)式為YES時, 結(jié)果就是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);
輸出結(jié)果:filterArray: (
1,
6
)
(3)NOT, !: 邏輯非, 對原有的表達(dá)式取反
例: NSNumber *testNumber = @1;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF != 1"];
if ([predicate evaluateWithObject:testNumber]) {
NSLog(@"testNumber = %@", testNumber);
}
else {
NSLog(@"不符合條件");
}
輸出結(jié)果: 不符合條件
3: 字符串比較運(yùn)算符:
(1)BEGINSWITH: 檢查某個字符串是否已指定的字符串開頭
例: NSString *testString = @"testString";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BEGINSWITH 't'"];
if ([predicate evaluateWithObject:testString]) {
NSLog(@"testString = %@", testString);
}
else {
NSLog(@"不符合條件");
}
輸出結(jié)果: testString = testString
(2)ENDSWITH:檢查某個字符串是否以指定的字符串結(jié)尾
(3)CONTAINS: 檢查某個字符串是否包含指定的字符串
例: NSString *testString = @"testString";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS 'ts'"];
if ([predicate evaluateWithObject:testString]) {
NSLog(@"testString = %@", testString);
}
else {
NSLog(@"不符合條件");
}
輸出結(jié)果: 不符合條件
備注: ts要用單引號' ' 括住, 否則會崩潰, 切記;
(4) LIKE: 檢查某個字符串是否匹配指定的字符串模板. 其之后可以跟 ? 代表一個字符 和 * 代表任意多個字符 兩個通配符;
例: "testString LIKE '*tS*'": 表示如果testString的值中包含ac則返回YES, 此時和CONTAINS相同
NSString *testString = @"testString";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF LIKE '*tS*'"];
if ([predicate evaluateWithObject:testString]) {
NSLog(@"testString = %@", testString);
}
else {
NSLog(@"不符合條件");
}
輸出結(jié)果:testString = testString
例: "testString LIKE '?tS*", 表示testString的第2, 3個字符為ac時, 返回YES
NSString *testString = @"testString";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF LIKE '?tS*'"];
if ([predicate evaluateWithObject:testString]) {
NSLog(@"testString = %@", testString);
}
else {
NSLog(@"不符合條件");
}
輸出結(jié)果: 不符合條件
(5)MATCHES: 檢查某個字符串是否匹配指定的正則表達(dá)式。雖然正則表達(dá)式的執(zhí)行效率是最低的, 但其功能是最強(qiáng)大的, 也是我們 最常用 的。
注: 字符串比較都是區(qū)分 大小寫 和重音符號 的。如:café和cafe是不一樣的,Cafe和cafe也是不一樣的。如果希望字符串比較運(yùn)算不區(qū)分大小寫和重音符號, 請?jiān)谶@些運(yùn)算符后使用 [c], [d]選項(xiàng)。其中[c] 是不區(qū)分大小寫,[d]是不區(qū)分重音符號,其寫在字符串比較運(yùn)算符之后,比如: testString LIKE[cd] 'cafe', 那么不論testString是cafe,Cafe還是café上面的表達(dá)式都會返回YES。
4. 集合運(yùn)算符
(1)ANY、SOME: 集合中任意一個元素滿足條件,就返回YES。
NSArray *testArray = @[@"zhao",@"qian",@"sun"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY SELF BEGINSWITH 'su'"];
if ([predicate evaluateWithObject:testArray]) {
NSLog(@"testArray = %@", testArray);
}
else {
NSLog(@"不符合條件");
}
輸出結(jié)果:testArray = (
zhao,
qian,
sun
)
(2)ALL: 集合中所有元素都滿足條件,才返回YES
NSArray *testArray = @[@"zhao",@"qian",@"sun"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ALL SELF BEGINSWITH 'su'"];
if ([predicate evaluateWithObject:testArray]) {
NSLog(@"testArray = %@", testArray);
}
else {
NSLog(@"不符合條件");
}
輸出結(jié)果: 不符合條件
(3)NONE: 集合中沒有任何元素滿足條件就返回YES
NSArray *testArray = @[@4, @5, @6, @7];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NONE SELF < 3"];
if ([predicate evaluateWithObject:testArray]) {
NSLog(@"testArray = %@", testArray);
}
else {
NSLog(@"不符合條件");
}
輸出結(jié)果:testArray = (
4,
5,
6,
7
)
(4)IN: 等價(jià)于SQL語句中的IN運(yùn)算符, 只有當(dāng)左邊表達(dá)式或值出現(xiàn)在右邊的集合中才會返回YES
NSArray *filterArray = @[@"ab", @"abc"];
NSArray *testArray = @[@"a", @"ab", @"abc", @"abcd"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", filterArray];
NSLog(@"%@",[testArray filteredArrayUsingPredicate:predicate]);
輸出結(jié)果:(
a,
abcd
)
上面那段代碼的作用是將testArray中和filterArray中相同的元素去除
5.直接量
在謂詞表達(dá)式中可以使用如下直接量:
(1)FALSE、NO:代表邏輯假
(2)TRUE、YES:代表邏輯真
(3)NULL、NIL:代表空值
(4)SELF:代表正在被判斷的對象自身
(5)"string"或'string':代表字符串
(6)數(shù)組:和c中的寫法相同, 如:{'one','two','three'}
(7)數(shù)值: 包括證書、小數(shù)和科學(xué)計(jì)數(shù)法表示的形式
(8)十六進(jìn)制數(shù): 0x開頭的數(shù)字
(9)八進(jìn)制: 0o開頭的數(shù)字
(10)二進(jìn)制:0b開頭的數(shù)字
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:@""];
例一:
定義模型:
ZLPersonModel.h
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, ZLPersonSex){
ZLPersonSexMale = 0,
ZLPersonSexFemale
};
@interface ZLPersonModel : NSObject
/** 姓名 */
@property (nonatomic, copy) NSString *name;
/** 年齡 */
@property (nonatomic, assign, readonly) NSUInteger age;
/** 性別 */
@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 {
self = [super init];
if (self) {
_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];
}
@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*'"];
//輸出結(jié)果: sunnyzl: 1, jack: 0
NSLog(@"sunnyzl: %d, jack: %d",[pred1 evaluateWithObject:sunnyzl], [pred1 evaluateWithObject:jack]);
//2: 判斷年齡是否大于25
NSPredicate *pred2 = [NSPredicate predicateWithFormat:@"age > 25"];
//輸出結(jié)果: sunnyzl的年齡是否大于25: 1, jack的年齡是否大于25: 0
NSLog(@"sunnyzl的年齡是否大于25: %d, jack的年齡是否大于25: %d",[pred2 evaluateWithObject:sunnyzl], [pred2 evaluateWithObject:jack]);
2.使用謂詞過濾集合(很重要)
其實(shí) 謂詞 本身就代表了一個邏輯條件,計(jì)算謂詞之后返回的結(jié)果永遠(yuǎn)為BOOL類型的值。而謂詞最常用的功能就是對集合進(jìn)行過濾。當(dāng)程序使用謂詞對集合元素進(jìn)行過濾時,程序會自動遍歷其元素,并根據(jù)集合元素來計(jì)算謂詞的值,當(dāng)這個集合中的元素計(jì)算謂詞并返回YES時,這個元素才會被保留下來。請注意 程序會自動遍歷其元素,它會將自動遍歷過之后返回為YES的值重新組合成一個集合返回。
//NSArray提供了如下方法使用謂詞來過濾集合
//根據(jù)指定的謂詞過濾集合,并將符合條件的元素組成新的集合返回(應(yīng)用于NSArray中)
//參數(shù): 指定的謂詞
//返回:符合謂詞條件的元素組成的集合
- (NSArray<ObjectType> *)filteredArrayUsingPredicate:(NSPredicate *)predicate;
//NSMutableArray提供了如下方法使用謂詞來過濾集合
//根據(jù)指定的謂詞過濾集合,剔除集合中不符合條件的元素
//參數(shù): 指定的謂詞
- (void)filterUsingPredicate:(NSPredicate *)predicate;
//NSSet提供了如下方法使用謂詞來過濾集合
//作用同NSArray中的方法
- (NSSet<ObjectType> *)filteredSetUsingPredicate:(NSPredicate *)predicate;
//NSMutableSet提供了如下方法使用謂詞來過濾集合
//作用同NSMutableArray中的方法
- (void)filterUsingPredicate:(NSPredicate *)predicate API_AVAILABLE(macos(10.5), ios(3.0), watchos(2.0), tvos(9.0));
備注: 通過上面的描述可以看出, 使用謂詞過濾不可變集合和可變集合的區(qū)別是: 過濾不可變集合時, 會 返回符合條件 的集合元素組成的新集合; 過濾可變集合時, 沒有返回值, 會 直接剔除不符合條件 的集合元素.
例一:
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:ZLPersonSexFemale],
[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 = %@",newArray);
輸出結(jié)果:arrayM = (
60,
70
)
newArray = (
"[name = Jackson, age = 30, sex = ZLPersonSexMale]",
"[name = Johnson, age = 35, sex = ZLPersonSexMale]"
)
3. 在謂詞中使用占位符參數(shù)
我們上面所有的例子中 謂詞 總是 固定的, 然而我們在現(xiàn)實(shí)中處理變量時決定了謂詞應(yīng)該是 可變的. 下面我們來看看如何讓謂詞變化起來:
首先: 如果我們想在謂詞表達(dá)式中使用變量,那么我們需要了解下列兩種占位符:
%K: 用于動態(tài)傳入屬性名
%@: 用于動態(tài)設(shè)置屬性值
除此之外, 還可以在謂詞表達(dá)式中使用動態(tài)改變的屬性值, 就像環(huán)境變量一樣:
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF CONTAINS $VALUE"];
上面表達(dá)式中, $VALUE是一個可以動態(tài)變化的值, 它最后其實(shí)是在字典中的一個key值, 所以可以根據(jù)你的需要寫入不同的值, 但是必須有, 然后隨著程序改變$VALUE這個 謂詞 表達(dá)式的比較條件就可以動態(tài)改變.
例一:
NSArray *array = @[[ZLPersonModel personWithName:@"Jack" age:20 sex:ZLPersonSexMale],
[ZLPersonModel personWithName:@"Rose" age:22 sex:ZLPersonSexFemale],
[ZLPersonModel personWithName:@"Jackson" age:30 sex:ZLPersonSexMale],
[ZLPersonModel personWithName:@"Johnson" age:35 sex:ZLPersonSexMale]];
//定義一個property來存放屬性名, 定義一個value來存放值
NSString *property = @"name";
NSString *value = @"Jack";
//該謂詞的作用是如果property屬性含有值value時就取出放入新的數(shù)組內(nèi), 這里是name包含Jack
NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K CONTAINS %@", property, value];
NSArray *newArray = [array filteredArrayUsingPredicate:pred];
NSLog(@"newArray = %@",newArray);
//創(chuàng)建謂詞, 屬性名改為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);
備注:
//用常數(shù)值代替變量
//參數(shù): 替換變量的字典
//返回: 替換變量后的謂詞表達(dá)式
- (instancetype)predicateWithSubstitutionVariables:(NSDictionary<NSString *, id> *)variables;
輸出結(jié)果為:
newArray = (
"[name = Jack, age = 20, sex = ZLPersonSexMale]",
"[name = Jackson age = 30, sex = ZLPersonSexMale]"
)
newArray1 = (
"[name = Jackson, age = 30, sex = ZLPersonSexMale]",
"[name = Johnson, age = 35, sex = ZLPersonSexMale]"
)
newArray2 = (
"[name = Johnson, age = 35, sex = ZLPersonSexMale]"
)