NSPredicate詳解(轉載)

轉載自:http://www.cocoachina.com/ios/20160111/14926.html

1、大小判斷

>=,=>:判斷左邊表達式的值是否大于或等于右邊表達式的值

<=,=<:判斷右邊表達式的值是否小于或等于右邊表達式的值

>:判斷左邊表達式的值是否大于右邊表達式的值

<:判斷左邊表達式的值是否小于右邊表達式的值

!=、<>:判斷兩個表達式是否不相等

BETWEEN:BETWEEN表達式必須滿足表達式 BETWEEN {下限,上限}的格式,要求該表達式必須大于或等于下限,并小于或等于上限

NSNumber *testNumber = @123;

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF BETWEEN {100, 200}"];

if ([predicate evaluateWithObject:testNumber]) {

NSLog(@"testString:%@", testNumber);

} else {

NSLog(@"不符合條件");

}

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

)

OR、||:邏輯或,要求其中一個表達式為YES時,結果就是YES

NOT、 !:邏輯非,對原有的表達式取反

3.字符串比較運算符

BEGINSWITH:檢查某個字符串是否以指定的字符串開頭(如判斷字符串是否以a開頭:BEGINSWITH 'a')

ENDSWITH:檢查某個字符串是否以指定的字符串結尾

CONTAINS:檢查某個字符串是否包含指定的字符串

LIKE:檢查某個字符串是否匹配指定的字符串模板。其之后可以跟?代表一個字符和*代表任意多個字符兩個通配符。比如"name LIKE '*ac*'",這表示name的值中包含ac則返回YES;"name LIKE '?ac*'",表示name的第2、3個字符為ac時返回YES。

MATCHES:檢查某個字符串是否匹配指定的正則表達式。雖然正則表達式的執行效率是最低的,但其功能是最強大的,也是我們最常用的。

注:字符串比較都是區分大小寫和重音符號的。如:café和cafe是不一樣的,Cafe和cafe也是不一樣的。如果希望字符串比較運算不區分大小寫和重音符號,請在這些運算符后使用[c],[d]選項。其中[c]是不區分大小寫,[d]是不區分重音符號,其寫在字符串比較運算符之后,比如:name LIKE[cd] 'cafe',那么不論name是cafe、Cafe還是café上面的表達式都會返回YES。

4.集合運算符

ANY、SOME:集合中任意一個元素滿足條件,就返回YES。

ALL:集合中所有元素都滿足條件,才返回YES。

NONE:集合中沒有任何元素滿足條件就返回YES。如:NONE person.age < 18,表示person集合中所有元素的age>=18時,才返回YES。

IN:等價于SQL語句中的IN運算符,只有當左邊表達式或值出現在右邊的集合中才會返回YES。我們通過一個例子來看一下

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

)

array[index]:返回array數組中index索引處的元素

array[FIRST]:返回array數組中第一個元素

array[LAST]:返回array數組中最后一個元素

array[SIZE]:返回array數組中元素的個數

5.直接量

在謂詞表達式中可以使用如下直接量

FALSE、NO:代表邏輯假

TRUE、YES:代表邏輯真

NULL、NIL:代表空值

SELF:代表正在被判斷的對象自身

"string"或'string':代表字符串

數組:和c中的寫法相同,如:{'one', 'two', 'three'}。

數值:包括證書、小數和科學計數法表示的形式

十六進制數:0x開頭的數字

八進制:0o開頭的數字

二進制:0b開頭的數字

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.定義謂詞

一般我們使用下列方法來定義一個謂詞

1

NSPredicate *predicate = [NSPredicate predicateWithFormat:];

下面我們通過幾個簡單的例子來看看它該如何使用:

首先我們需要定義一個模型,因為示例中需要用到它

ZLPersonModel.h

#import typedef NS_ENUM(NSInteger, ZLPersonSex) {

ZLPersonSexMale = 0,

ZLPersonSexFamale

};

@interface ZLPersonModel : NSObject

/** NSString 姓名 */

@property (nonatomic, copy) NSString *name;

/** NSUInteger 年齡 */

@property (nonatomic, assign) NSUInteger age;

/** ZLPersonSex 性別 */

@property (nonatomic, assign) ZLPersonSex sex;

+ (instancetype)personWithName:(NSString *)name age:(NSUInteger)age sex:(ZLPersonSex)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];

}

我們想要的效果是字符串中有特殊字符時就返回YES,然而夢想是美好的,現實是殘酷的

讓我們看看這悲催的結局

NSString *testString = @"!";

NSLog(@"是否含有特殊字符:%d", [self checkSpecialCharacter:testString]);

//? 當testString為一個特殊字符時,我們驚喜的發現輸出為

//? 是否含有特殊字符:1

看到這里我們心里猛然一喜,這tmd根本沒問題嘛

讓我們修改下testString的值

NSString *testString = @"!~";

NSLog(@"%d", [self checkSpecialCharacter:testString]);

//? 我們會發現悲催的結局來了輸出為

//? 是否含有特殊字符:0

再次修改testString的值

NSString *testString = @"abc!~d";

NSLog(@"%d", [self checkSpecialCharacter:testString]);

//? 我們會發現輸出為

//? 是否含有特殊字符:0

這總與我們的想法事與愿違,看到這里我們會發現謂詞對正則并不像我們使用NSRegularExpression時匹配的那么好,究其原因是為什么呢?我們用NSRegularExpression時會發現匹配到一個結果時就會存入數組,再從匹配到的位置繼續向下匹配。

然而NSPredicate并不會做這樣的自動操作,我們最終發現在NSPredicate輸入[`~!@#$^&*()=|{}':;',\[\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]正則表達式時和寫成^[`~!@#$^&*()=|{}':;',\[\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]$的效果是一樣的。

所以通過這個例子我們總結出來,只有在正則表達式為^表達式$時才使用謂詞,而不是所有情況都使用。

那么我們是不是因為這一點就摒棄它了呢,答案是否定的。因為雖然NSPredicate有這么一點瑕疵,但是它總體帶給我們的便利其實除了正則表達式匹配時的這個問題外是更多的。

2.使用謂詞過濾集合

此部分是我們需要掌握的重點,因為從這里我們就可以看到謂詞的真正的強大之處

其實謂詞本身就代表了一個邏輯條件,計算謂詞之后返回的結果永遠為BOOL類型的值。而謂詞最常用的功能就是對集合進行過濾。當程序使用謂詞對集合元素進行過濾時,程序會自動遍歷其元素,并根據集合元素來計算謂詞的值,當這個集合中的元素計算謂詞并返回YES時,這個元素才會被保留下來。請注意程序會自動遍歷其元素,它會將自動遍歷過之后返回為YES的值重新組合成一個集合返回。

其實類似于我們使用tableView設置索引時使用的下段代碼

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView

{

return [self.cityGroup valueForKey:@"title"];

}

中的[self.cityGroup valueForKey:@"title"]。它的作用是遍歷所有title并將得到的值組成新的數組。

NSArray提供了如下方法使用謂詞來過濾集合

- (NSArray*)filteredArrayUsingPredicate:(NSPredicate *)predicate:使用指定的謂詞過濾NSArray集合,返回符合條件的元素組成的新集合

NSMutableArray提供了如下方法使用謂詞來過濾集合

- (void)filterUsingPredicate:(NSPredicate *)predicate:使用指定的謂詞過濾NSMutableArray,剔除集合中不符合條件的元素

NSSet提供了如下方法使用謂詞來過濾集合

- (NSSet*)filteredSetUsingPredicate:(NSPredicate *)predicate NS_AVAILABLE(10_5, 3_0):作用同NSArray中的方法

NSMutableSet提供了如下方法使用謂詞來過濾集合

- (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循環等等??梢钥闯鯪SPredicate的出現為我們節省了大量的時間和精力。

3.在謂詞中使用占位符參數

我們上面所有的例子中謂詞總是固定的,然而我們在現實中處理變量時決定了謂詞應該是可變的。下面我們來看看如果讓謂詞變化起來。

首先如果我們想在謂詞表達式中使用變量,那么我們需要了解下列兩種占位符:

%K:用于動態傳入屬性名

%@:用于動態設置屬性值

其實相當于變量名與變量值

除此之外,還可以在謂詞表達式中使用動態改變的屬性值,就像環境變量一樣

1

NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF CONTAINS $VALUE"];

上述表達式中,$VALUE是一個可以動態變化的值,它其實最后是在字典中的一個key,所以可以根據你的需要寫不同的值,但是必須有$開頭,隨著程序改變$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"];

// 指定$SUBSTR的值為 25? ? 這里注釋中的$SUBSTR改為$VALUE

NSPredicate *pred1 = [predTemp predicateWithSubstitutionVariables:@{@"VALUE" : @25}];

NSArray *newArray1 = [array filteredArrayUsingPredicate:pred1];

NSLog(@"newArray1:%@", newArray1);

//? 修改 $SUBSTR的值為32,? 這里注釋中的SUBSTR改為$VALUE

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的含義。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容

  • 首先,我們需要知道何謂謂詞,讓我們看看官方的解釋:The NSPredicate class is used to...
    旭日飛揚閱讀 1,535評論 0 0
  • NSPredicate類是用來定義邏輯條件約束的獲取或內存中的過濾搜索。 可以使用謂詞來表示邏輯條件,用于描述對象...
    靜守幸福閱讀 507評論 0 0
  • 前言 有時我們需要在一大段長文本中過濾出我們需要的字段,或者檢驗該文本是否符合要求(該文本是否是郵箱,鏈接,電話號...
    進無盡閱讀 974評論 0 1
  • 什么是謂詞查詢 NSPredicate類是用來定義邏輯條件約束的獲取或內存中的過濾搜索。 可以使用謂詞表示邏輯條件...
    奔跑的_猿閱讀 1,888評論 0 1
  • 我錯了嗎?→_→ 認錯,我們從很小很小的時候就接觸到了,從華盛頓砍樹的故事,在到自己的親身經歷,必然少不了接觸到這...
    麟寶辰閱讀 1,268評論 0 1