【Objective-C基础】NSPredicate

原文:http://www.cocoachina.com/industry/20140321/8024.html
一、简介 
  NSPredicate是一个Foundation类,它指定数据被获取或者过滤的方式。它的查询语言就像SQL的WHERE和正则表达式的交叉一样,提供了具有表现力的,自然语言界面来定义一个集合被搜寻的逻辑条件。
 相比较抽象的谈论它,展示NSPredicate的使用方法更加容易:
 
 索引 1 2 3 4
 名 Alice Bob Charlie Quentin
 姓 Smith Jones Smith Alberts
 年龄 24 27 33 31
   
       

@interface Person : NSObject  
@property NSString * firstName ;  
@property NSString * lastName ;  
@property NSNumber * age ;  
@end  

 

@implementation Person  
 
- ( NSString *) description {  
    return [ NSString stringWithFormat :@ "%@ %@" , self . firstName , self . lastName ];  
}  
 
@end

 
 

#pragma mark -  
 
NSArray * firstNames = @[ @ "Alice" , @ "Bob" , @ "Charlie" , @ "Quentin" ];  
NSArray * lastNames = @[ @ "Smith" , @ "Jones" , @ "Smith" , @ "Alberts" ];  
NSArray * ages = @[ @ 24 , @ 27 , @ 33 , @ 31 ];  
 
NSMutableArray * people = [ NSMutableArray array ];  
[ firstNames enumerateObjectsUsingBlock :^( id obj , NSUInteger idx , BOOL * stop ) {  
    Person * person = [[ Person alloc ] init ];  
    person . firstName = firstNames [ idx ];  
    person . lastName = lastNames [ idx ];  
    person . age = ages [ idx ];  
    [ people addObject : person ];  
}];  
 
NSPredicate * bobPredicate = [ NSPredicate predicateWithFormat :@ "firstName = 'Bob'" ];  
NSPredicate * smithPredicate = [ NSPredicate predicateWithFormat :@ "lastName = %@" , @ "Smith" ];  
NSPredicate * thirtiesPredicate = [ NSPredicate predicateWithFormat :@ "age >= 30" ];  
 
// ["Bob Jones"] 
NSLog(@"Bobs: %@", [people filteredArrayUsingPredicate:bobPredicate]); 
 
// ["Alice Smith", "Charlie Smith"] 
NSLog(@"Smiths: %@", [people filteredArrayUsingPredicate:smithPredicate]); 
 
// ["Charlie Smith", "Quentin Alberts"] 
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)评估,而不像集合那样在内存中被过滤。
四、谓词语法
1、替换
%@是对值为字符串,数字或者日期的对象的替换值。
%K是key path的替换值。
NSPredicate *ageIs33Predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"age", @33]; 
 
// ["Charlie Smith"] 
NSLog(@"Age 33: %@", [people filteredArrayUsingPredicate:ageIs33Predicate]); 
$VARIABLE_NAME是可以被NSPredicate -predicateWithSubstitutionVariables:替换的值。
NSPredicate *namesBeginningWithLetterPredicate = [NSPredicate predicateWithFormat:@"(firstName BEGINSWITH[cd] $letter) OR (lastName BEGINSWITH[cd] $letter)"]; 
 
// ["Alice Smith", "Quentin Alberts"] 
NSLog(@"'A' Names: %@", [people filteredArrayUsingPredicate:[namesBeginningWithLetterPredicate predicateWithSubstitutionVariables:@{@"letter": @"A"}]]); 
 
2、基本比较
=, ==:左边的表达式和右边的表达式相等。
>=, =>:左边的表达式大于或者等于右边的表达式。
<=, =<:左边的表达式小于等于右边的表达式。
>:左边的表达式大于右边的表达式。
<:左边的表达式小于右边的表达式。
!=, <>:左边的表达式不等于右边的表达式。
 
3、BETWEEN:左边的表达式等于右边的表达式的值或者介于它们之间。右边是一个有两个指定上限和下限的数值的数列(指定顺序的数列)。比如,1 BETWEEN { 0 , 33 },或者$INPUT BETWEEN { $LOWER, $UPPER }。
 
4、基本复合谓词
AND, &&:逻辑与.
OR, ||:逻辑或.
NOT, !:逻辑非.
 
5、字符串比较
字符串比较在默认的情况下是区分大小写和音调的。你可以在方括号中用关键字符c和d来修改操作符以相应的指定不区分大小写和变音符号,比如firstname BEGINSWITH[cd] $FIRST_NAME。
BEGINSWITH:左边的表达式以右边的表达式作为开始。
CONTAINS:左边的表达式包含右边的表达式。
ENDSWITH:左边的表达式以右边的表达式作为结束。
LIKE:左边的表达式等于右边的表达式:?和*可作为通配符,其中?匹配1个字符,*匹配0个或者多个字符。
MATCHES:左边的表达式根据ICU v3(更多内容请查看ICU User Guide for Regular Expressions)的regex风格比较,等于右边的表达式。
 
6、关系操作
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' }。
  7、数组操作
array[index]:指定数组中特定索引处的元素。
array[FIRST]:指定数组中的第一个元素。
array[LAST]:指定数组中的最后一个元素。
array[SIZE]:指定数组的大小。
  8、布尔值谓词
TRUEPREDICATE:结果始终为真的谓词。
FALSEPREDICATE:结果始终为假的谓词。
四、高级使用 
1、NSCompoundPredicate
我们见过与&或被用在谓词格式字符串中以创建复合谓词。然而,我们也可以用NSCompoundPredicate来完成同样的工作。
 例如,下列谓词是相等的:
[NSCompoundPredicate andPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"age > 25"], [NSPredicate predicateWithFormat:@"firstName = %@", @"Quentin"]]]; 
 
[NSPredicate predicateWithFormat:@"(age > 25) AND (firstName = %@)", @"Quentin"]; 
虽然语法字符串文字更加容易输入,但是在有的时候,你需要结合现有的谓词。在那些情况下,你可以使用NSCompoundPredicate -andPredicateWithSubpredicates:&-orPredicateWithSubpredicates:。
 
2、NSComparisonPredicate
同样的,如果你在读过上周的文章之后发现你使用了太多的NSExpression的话,NSComparisonPredicate可以帮助你解决这个问题。
 就像NSCompoundPredicate一样,NSComparisonPredicate从子部件构建了一个NSPredicate--在这种情况下,左侧和右侧都是NSExpression。 分析它的类的构造函数可以让我们一窥NSPredicate的格式字符串是如何解析的:
+ (NSPredicate *)predicateWithLeftExpression:(NSExpression *)lhs 
                             rightExpression:(NSExpression *)rhs 
                                    modifier:(NSComparisonPredicateModifier)modifier 
                                        type:(NSPredicateOperatorType)type 
                                     options:(NSUInteger)options 

参数
lhs:左边的表达式。
rhs:右边的表达式。
modifier:应用的修改符。(ANY或者ALL)
type:谓词运算符类型。
options:要应用的选项。没有选项的话则为0。
 
NSComparisonPredicate的 type类型
enum { 
   NSLessThanPredicateOperatorType = 0, 
   NSLessThanOrEqualToPredicateOperatorType, 
   NSGreaterThanPredicateOperatorType, 
   NSGreaterThanOrEqualToPredicateOperatorType, 
   NSEqualToPredicateOperatorType, 
   NSNotEqualToPredicateOperatorType, 
   NSMatchesPredicateOperatorType, 
   NSLikePredicateOperatorType, 
   NSBeginsWithPredicateOperatorType, 
   NSEndsWithPredicateOperatorType, 
   NSInPredicateOperatorType, 
   NSCustomSelectorPredicateOperatorType, 
   NSContainsPredicateOperatorType, 
   NSBetweenPredicateOperatorType 
}; 
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:。

NSPredicate * shortNamePredicate = [ NSPredicate predicateWithBlock :^ BOOL ( id evaluatedObject , NSDictionary * bindings ) {  
            return [[ evaluatedObject firstName ] length ] <= 5 ;  
        }];  
 
// ["Alice Smith", "Bob Jones"] 
NSLog(@"Short Names: %@", [people filteredArrayUsingPredicate:shortNamePredicate]); 

...好吧,虽然使用predicateWithBlock:是懒人的做法,但它也并不是一无是处。
事实上,因为block可以封装任意的计算,所以有一个查询类是无法以NSPredicate格式字符串形式来表达的(比如对运行时被动态计算的值的评估)。而且当同一件事情可以用NSExpression结合自定义选择器来完成时,block为完成工作提供了一个方便的接口。
重要提示: 由predicateWithBlock:生成的NSPredicate不能用于由SQLite存储库支持的Core Data数据的提取要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值