NSPredicate的

轉自 http://www.cocoachina.com/industry/20140321/8024.htmlhtml

 NSPredicate是一個Foundation類,它指定數據被獲取或者過濾的方式。它的查詢語言就像SQL的WHERE和正則表達式的交叉同樣,提供了具備表現力的,天然語言界面來定義一個集合被搜尋的邏輯條件。正則表達式

 
相比較抽象的談論它,展現NSPredicate的使用方法更加容易,因此咱們來從新審視 NSSortDescriptor中使用的示例數據集吧:
 
索引 1 2 3 4
Alice Bob Charlie Quentin
Smith Jones Smith Alberts
年齡 24 27 33 31
 
  1. @interface Person : NSObject 
  2. @property NSString *firstName; 
  3. @property NSString *lastName; 
  4. @property NSNumber *age; 
  5. @end 
  6.  
  7. @implementation Person 
  8.  
  9. - (NSString *)description { 
  10.     return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName]; 
  11.  
  12. @end 
  13.  
  14. #pragma mark - 
  15.  
  16. NSArray *firstNames = @[ @"Alice", @"Bob", @"Charlie", @"Quentin" ]; 
  17. NSArray *lastNames = @[ @"Smith", @"Jones", @"Smith", @"Alberts" ]; 
  18. NSArray *ages = @[ @24, @27, @33, @31 ]; 
  19.  
  20. NSMutableArray *people = [NSMutableArray array]; 
  21. [firstNames enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
  22.     Person *person = [[Person alloc] init]; 
  23.     person.firstName = firstNames[idx]; 
  24.     person.lastName = lastNames[idx]; 
  25.     person.age = ages[idx]; 
  26.     [people addObject:person]; 
  27. }]; 
  28.  
  29. NSPredicate *bobPredicate = [NSPredicate predicateWithFormat:@"firstName = 'Bob'"]; 
  30. NSPredicate *smithPredicate = [NSPredicate predicateWithFormat:@"lastName = %@", @"Smith"]; 
  31. NSPredicate *thirtiesPredicate = [NSPredicate predicateWithFormat:@"age >= 30"]; 
  32.  
  33. // ["Bob Jones"] 
  34. NSLog(@"Bobs: %@", [people filteredArrayUsingPredicate:bobPredicate]); 
  35.  
  36. // ["Alice Smith", "Charlie Smith"] 
  37. NSLog(@"Smiths: %@", [people filteredArrayUsingPredicate:smithPredicate]); 
  38.  
  39. // ["Charlie Smith", "Quentin Alberts"] 
  40. NSLog(@"30's: %@", [people filteredArrayUsingPredicate:thirtiesPredicate]); 
 
集合中使用NSPredicate
Foundation提供使用謂詞(predicate)來過濾NSArray/NSMutableArray&NSSet/NSMutableSet的方法。
 
不可變的集合,NSArray&NSSet,有能夠經過評估接收到的predicate來返回一個不可變集合的方法filteredArrayUsingPredicate:和filteredSetUsingPredicate:。
 
可變集合,NSMutableArray&NSMutableSet,可使用方法filterUsingPredicate:,它能夠經過運行接收到的謂詞來移除評估結果爲FALSE的對象。
 
NSDictionary能夠用謂詞來過濾它的鍵和值(二者都爲NSArray對象)。NSOrderedSet能夠由過濾的NSArray或 NSSet生成一個新的有序的集,或者NSMutableSet能夠簡單的removeObjectsInArray:,來傳遞經過否認 predicate過濾的對象。
 
Core Data中使用NSPredicate
NSFetchRequest有一個predicate屬性,它能夠指定管理對象應該被獲取的邏輯條件。謂詞的使用規則在這裏一樣適用,惟一的 區別在於,在管理對象環境中,謂詞由持久化存儲助理(persistent store coordinator)評估,而不像集合那樣在內存中被過濾。
 
謂詞語法
替換
%@是對值爲字符串,數字或者日期的對象的替換值。
%K是key path的替換值。
  1. NSPredicate *ageIs33Predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"age", @33]; 
  2.  
  3. // ["Charlie Smith"] 
  4. NSLog(@"Age 33: %@", [people filteredArrayUsingPredicate:ageIs33Predicate]); 
$VARIABLE_NAME是能夠被NSPredicate -predicateWithSubstitutionVariables:替換的值。
  1. NSPredicate *namesBeginningWithLetterPredicate = [NSPredicate predicateWithFormat:@"(firstName BEGINSWITH[cd] $letter) OR (lastName BEGINSWITH[cd] $letter)"]; 
  2.  
  3. // ["Alice Smith", "Quentin Alberts"] 
  4. NSLog(@"'A' Names: %@", [people filteredArrayUsingPredicate:[namesBeginningWithLetterPredicate predicateWithSubstitutionVariables:@{@"letter": @"A"}]]); 
 
基本比較
=, ==:左邊的表達式和右邊的表達式相等。
>=, =>:左邊的表達式大於或者等於右邊的表達式。
<=, =<:左邊的表達式小於等於右邊的表達式。
>:左邊的表達式大於右邊的表達式。
<:左邊的表達式小於右邊的表達式。
!=, <>:左邊的表達式不等於右邊的表達式。
 
BETWEEN:左邊的表達式等於右邊的表達式的值或者介於它們之間。右邊是一個有兩個指定上限和下限的數值的數列(指定順序的數列)。好比,1 BETWEEN { 0 , 33 },或者$INPUT BETWEEN { $LOWER, $UPPER }。
 
基本複合謂詞
AND, &&:邏輯與.
OR, ||:邏輯或.
NOT, !:邏輯非.
 
字符串比較
字符串比較在默認的狀況下是區分大小寫和音調的。你能夠在方括號中用關鍵字符c和d來修改操做符以相應的指定不區分大小寫和變音符號,好比firstname BEGINSWITH[cd] $FIRST_NAME。
BEGINSWITH:左邊的表達式以右邊的表達式做爲開始。
CONTAINS:左邊的表達式包含右邊的表達式。
ENDSWITH:左邊的表達式以右邊的表達式做爲結束。
LIKE:左邊的表達式等於右邊的表達式:?和*可做爲通配符,其中?匹配1個字符,*匹配0個或者多個字符。
MATCHES:左邊的表達式根據ICU v3(更多內容請查看ICU User Guide for Regular Expressions)的regex風格比較,等於右邊的表達式。
 
合計操做
關係操做
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' }。
 
數組操做
array[index]:指定數組中特定索引處的元素。
array[FIRST]:指定數組中的第一個元素。
array[LAST]:指定數組中的最後一個元素。
array[SIZE]:指定數組的大小。
 
布爾值謂詞
TRUEPREDICATE:結果始終爲真的謂詞。
FALSEPREDICATE:結果始終爲假的謂詞。
 
NSCompoundPredicate
咱們見過與&或被用在謂詞格式字符串中以建立複合謂詞。然而,咱們也能夠用NSCompoundPredicate來完成一樣的工做。
 
例如,下列謂詞是相等的:
  1. [NSCompoundPredicate andPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"age > 25"], [NSPredicate predicateWithFormat:@"firstName = %@", @"Quentin"]]]; 
  2.  
  3. [NSPredicate predicateWithFormat:@"(age > 25) AND (firstName = %@)", @"Quentin"]; 
雖然語法字符串文字更加容易輸入,可是在有的時候,你須要結合現有的謂詞。在那些狀況下,你可使用NSCompoundPredicate -andPredicateWithSubpredicates:&-orPredicateWithSubpredicates:。
 
NSComparisonPredicate
一樣的,若是你在讀過 上週的文章以後發現你使用了太多的NSExpression的話,NSComparisonPredicate能夠幫助你解決這個問題。
 
就像NSCompoundPredicate同樣,NSComparisonPredicate從子部件構建了一個NSPredicate-- 在這種狀況下,左側和右側都是NSExpression。 分析它的類的構造函數可讓咱們一窺NSPredicate的格式字符串是如何解析的:
  1. + (NSPredicate *)predicateWithLeftExpression:(NSExpression *)lhs 
  2.                              rightExpression:(NSExpression *)rhs 
  3.                                     modifier:(NSComparisonPredicateModifier)modifier 
  4.                                         type:(NSPredicateOperatorType)type 
  5.                                      options:(NSUInteger)options 

參數
lhs:左邊的表達式。
rhs:右邊的表達式。
modifier:應用的修改符。(ANY或者ALL)
type:謂詞運算符類型。
options:要應用的選項。沒有選項的話則爲0。
 
NSComparisonPredicate類型
  1. enum { 
  2.    NSLessThanPredicateOperatorType = 0, 
  3.    NSLessThanOrEqualToPredicateOperatorType, 
  4.    NSGreaterThanPredicateOperatorType, 
  5.    NSGreaterThanOrEqualToPredicateOperatorType, 
  6.    NSEqualToPredicateOperatorType, 
  7.    NSNotEqualToPredicateOperatorType, 
  8.    NSMatchesPredicateOperatorType, 
  9.    NSLikePredicateOperatorType, 
  10.    NSBeginsWithPredicateOperatorType, 
  11.    NSEndsWithPredicateOperatorType, 
  12.    NSInPredicateOperatorType, 
  13.    NSCustomSelectorPredicateOperatorType, 
  14.    NSContainsPredicateOperatorType, 
  15.    NSBetweenPredicateOperatorType 
  16. }; 
  17. typedef NSUInteger NSPredicateOperatorType; 

NSComparisonPredicate選項
NSCaseInsensitivePredicateOption:不區分大小寫的謂詞。你經過在謂詞格式字符串中加入後面帶有[c]的字符串操做(好比,"NeXT" like[c] "next")來表達這一選項。
 
NSDiacriticInsensitivePredicateOption:忽視發音符號的謂詞。你經過在謂詞格式字符串中加入後面帶有[d]的字符串操做(好比,"naïve" like[d] "naive")來表達這一選項。
 
NSNormalizedPredicateOption: 表示待比較的字符串已經被預處理了。這一選項取代了NSCaseInsensitivePredicateOption和 NSDiacriticInsensitivePredicateOption,旨在用做性能優化的選項。你能夠經過在謂詞格式字符串中加入後面帶有 [n]的字符串(好比,"WXYZlan" matches[n] ".lan")來表達這一選項。
 
NSLocaleSensitivePredicateOption: 代表要使用<,<=,=,=>,> 做爲比較的字符串應該使用區域識別的方式處理。你能夠經過在<,<=,=,=>,>其中之一的操做符後加入[l](比 如,"straße" >[l] "strasse")以便在謂詞格式字符串表達這一選項。
 
Block謂詞
 
最後,若是你實在不肯意學習NSPredicate的格式語法,你也能夠學學NSPredicate +predicateWithBlock:。
  1. NSPredicate *shortNamePredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { 
  2.             return [[evaluatedObject firstName] length] <= 5; 
  3.         }]; 
  4.  
  5. // ["Alice Smith", "Bob Jones"] 
  6. NSLog(@"Short Names: %@", [people filteredArrayUsingPredicate:shortNamePredicate]); 
...好吧,雖然使用predicateWithBlock:是懶人的作法,但它也並非一無可取。
 
事實上,由於block能夠封裝任意的計算,因此有一個查詢類是沒法以NSPredicate格式字符串形式來表達的(好比對運行時被動態計算 的值的評估)。並且當同一件事情能夠用NSExpression結合自定義選擇器來完成時,block爲完成工做提供了一個方便的接口。
 
重要提示:由predicateWithBlock:生成的NSPredicate不能用於由SQLite存儲庫支持的Core Data數據的提取要求。
 
我知道我已經說過不少次了,但是NSPredicate真的是Cocoa的優點之一。其餘語言的第三方庫若是能有它一半的能力就已經很幸運了--更別提標準庫了。對於咱們這些應用和框架開發者來講,有它做爲標準組件使得咱們在處理數據時有了很大的優點。
 
和NSExpression同樣,NSPredicate一直在提醒咱們Foundation有多麼好:它不只僅十分有用,它精緻的構架和設計也是咱們寫代碼時靈感的來源。
相關文章
相關標籤/搜索