Foundation 之谓词 NSPredicate

相当多初学者都相当少接触NSPredicate,固然接触了NSPredicate
也不太通晓NSPredicate的选择意况。此处依照自家的使用,简介一下NSPredicate的使用意况:

小说转自http://nshipster.cn/示例代码可见GitHub

一、集结中动用NSPredicate

二、Core Data中使用NSPredicate

三、谓词语法1、替换2、基本比较3、基本复合谓词4、字符串相比5、合计操作关系操作数组操作6、布尔值谓词

四、NSCompoundPredicate

五、NSComparisonPredicate1、参数2、NSComparisonPredicate类型3、NSComparisonPredicate选项

六、Block谓词

NSPredicate
首就算用来查询、条件过滤;最常用的气象固然在自定义的多少模型对象中依照准则来询问有关音信,举个例子在堂弟大通信录中依据个人信息的Model所含有的name属性,来实行检索**
简言之** NSPredicate能够判明有些对象的某一个属性是还是不是顺应某一尺码

NSPredicate是三个Foundation类,它钦点数量被获取或然过滤的秘诀。它的询问语言就如SQL的WHERE和正则表明式的接力一样,提供了富有表现力的,自然语言分界面来定义贰个聚众被寻找的逻辑条件。

  • NSPredict 谓词能够由此定义三个逻辑条件,来搜寻查询、过滤新闻
  • NSPredict主要含有四个子类:NSComparisonPredicate、NSCompoundPredicate、NSExpression

绝相比空虚的研讨它,呈现NSPredicate的使用办法特别轻易,所以我们来重新审视NSSortDescriptor中采取的演示数据集吧:

在介绍NSPredict的行使在此以前,大家亟须先要了然哪些科学的书写谓词表明式

索引 0 1 2 3
Alice Bob Charlie Quentin
Smith Jones Smith Alberts
年龄 24 27 33 31
  • 正如运算符

  • = 、 == :判别多个表明式是还是不是等于

  • >= 、=>: 左边表达式是还是不是高于或等于右边表明式

  • <= 、 =< :侧面表明式是还是不是低于或等于右边表明式

  • > 、< :左侧表明式是还是不是越过、小于侧面表明式

  • != 、<>: 多少个表达式是或不是不等于

  • BETWEEN :”表明式 BEYWEEN {最小值,最大值}“
    ,说明式必得高出等于最小值或小于等于最大值

  • 逻辑运算符

  • AND、&& :五个表明式都为真是,结果为真;有假则结果为假

  • O本田UR-V、|| :多少个说明式有叁个结果为真,结果为真;同为假,则结果为假

  • NOT 、!: 表达式结果取反

  • 字符串正如运算符

  • BEGINSWITH :字符串是还是不是以某一子字符串早先

  • ENDSWITH : 字符串是或不是以某一子字符串结尾

  • CONTAINS :字符串是还是不是包罗某一子字符串

  • LIKE :字符串是不是合营内定的字符串模板

    • 模板中得以蕴涵通配符: *、?
    • title LIKE *abc?
      :title现存大肆多的字符串,结尾必须为abc+放肆一个字符
  • MATCHES :
    字符串是不是合营钦定的正则表达式;正则表明式成效壮大,然则试行成效低。能用谓词表明式的就不要用正则表达式注意:字符串相比运算符默许区分轻重缓急写和重音符号

Objective-C

1.一旦希望字符串比较运算符不区分轻重缓急写,能够再运算符后增添[c]2.若是希望字符串相比较运算符不区分重音符号,可以再运算符后增添[d]一般都以在运算符前边增添[cd],代表不区分轻重缓急写和重音符号

@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]);
  • 集聚操作相关的运算符

  • ANY 、SOME :群集中大肆二个因素满意条件,重临YES

  • ALL :集结中多有成分满足条件,再次回到YES

  • NONE :集结中任何因素不满意条件,再次回到YES

  • IN :左侧的表述式 在侧边的联谊中存在,再次来到YES

  • array[index] : 重临数组index索引处的成分

  • array[FIRST] : 再次来到数组第一个成分

  • array[LAST] : 重临数组最终贰个要素

  • array[SIZE] : 重回数组元素个数

  • 谓词表明式中的间接量

  • FALSE、NO : 逻辑假

  • TRUE、YES : 逻辑真

  • NULL、NIL : 空值

  • SELF :被剖断的目的自己

  • “text” : 字符串

  • 数组:数组成分以泰语逗号隔离

  • 数值直接量:整数、小数、科学工夫法

  • 各进制数:0x、0o、0b注意:谓词表明式中” “与’ ‘效果同样,但是“
    ”与‘ ’应该协作

  • 保留字:大写单词是保留字MATCHES、CONTAINS、BEGINSWITH、ENDSWIHT、BETWEEN、NULL、NIL、SELF、AND、O大切诺基、IN、NOT、ALL、ANY、SOME、NONE、LIKE、CASEINSENSITIVE、CI、TRUE、YES、FALSE、NO、FI科雷傲ST、LAST、SIZE、ANYKEY、SUBQUE福睿斯Y、CAST、TRUEPREDICATE、FALSEOREDICATE

Foundation提供使用谓词(predicate)来过滤NSArrayNSMutableArray&NSSetNSMutableSet的方法。

不可变的会集,NSArray&NSSet,有能够透过评估接收到的predicate来回到三个不可变集合的点子filteredArrayUsingPredicate:filteredSetUsingPredicate:

//以一个NSPredict字符串来创建一个NSPredict对象+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat argumentArray:(nullable NSArray *)arguments;+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat arguments:argList;//通过一个对象来计算谓词的结果 真/假- evaluateWithObject:(nullable id)object;

可变集合,NSMutableArray&NSMutableSet,能够采纳格局filterUsingPredicate:,它能够透过运转接收到的谓词来移除评估结果为FALSE的对象。

  • 以身作则代码

NSDictionary能够用谓词来过滤它的键和值(两个都为NSArray对象)。NSOrderedSet能够由过滤的NSArrayNSSet扭转贰个新的稳步的集,只怕NSMutableSet能够回顾的removeObjectsInArray:,来传递通过_否定_predicate过滤的目的。

NSFetchRequest有一个predicate质量,它能够钦赐管理对象应该被获取的逻辑条件。谓词的应用法则在此地一样适用,独一的分别在于,在管理对象处境中,谓词由悠久化存款和储蓄助理(persistent
store coordinator)评估,而不像集合那样在内部存款和储蓄器中被过滤。

 ZZYPerson * person1 = [[ZZYPerson alloc]initWithName:@"zhang san" Age:@"21"]; NSPredicate * pred1 = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@",@"san"]; NSPredicate * pred2 = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] 'san'"]; //注意第二种写法要将字符串用单引号包起来 BOOL isHave = [pred1 evaluateWithObject:person1]; NSLog(@"%d",isHave); //输出值为:1 NSLog(@"%@---%@",person1.name,person1.age);//输出值为:zhang san---21

替换

  • %@是对值为字符串,数字大概日期的目的的轮换值。
  • %K是key path的更迭值。

Objective-C

NSPredicate *ageIs33Predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"age", @33];// ["Charlie Smith"]NSLog(@"Age 33: %@", [people filteredArrayUsingPredicate:ageIs33Predicate]);
  • $VARIABLE_NAME是可以被NSPredicate -predicateWithSubstitutionVariables:轮换的值。

Objective-C

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"}]]);

** 注意
**上述代码中pred第22中学的写法,字符串要用单引号括起来(例如sql语句中的字符串也要包涵起来)

骨干相比

  • =, ==:侧边的表达式和左侧的表达式相等。
  • >=, =>:左边的表达式大于恐怕等于左边的表达式。
  • <=, =<:右侧的表明式小于等于左侧的表达式。
  • >:左侧包车型地铁表明式大于侧面的表达式。
  • <:左侧的表达式小于侧边的表明式。
  • !=, <>:侧面的表明式不等于左边的表明式。
  • BETWEEN:侧面的表明式等于侧面的表明式的值只怕介于它们中间。侧边是二个有三个钦命上限和下限的数值的数列。譬喻,1 BETWEEN { 0 , 33 },或者$INPUT BETWEEN { $LOWER, $UPPER }
  • NSPredict 本质上正是三个逻辑条件,NSPredict 运算的结果正是贰个BOOL值
  • NSPredict 一个相比较常用的效劳正是对集合元素的过滤;
    自动遍历集合成分——>根据成分判定 NSPredict
    的结果——>结果为YES时,集结成分保存
  • 小心谓词过滤不可变群集,结果再次来到符合条件的新会集;谓词过滤可变会集,直接将集结中不符合条件的元素去掉

主干复合谓词

  • 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风格相比,等于左边的表达式。
@interface NSArray<ObjectType> (NSPredicateSupport)//根据谓词条件过滤数组,返回符合条件的元素组成的新数组- (NSArray<ObjectType> *)filteredArrayUsingPredicate:(NSPredicate *)predicate; // evaluate a predicate against an array of objects and return a filtered array@end@interface NSMutableArray<ObjectType> (NSPredicateSupport)//根据谓词条件过滤数组,去掉数组中不符合条件的的元素- filterUsingPredicate:(NSPredicate *)predicate; // evaluate a predicate against an array of objects and filter the mutable array directly@end@interface NSSet<ObjectType> (NSPredicateSupport)////根据谓词条件过滤集合,返回符合条件的元素组成的新集合- (NSSet<ObjectType> *)filteredSetUsingPredicate:(NSPredicate *)predicate NS_AVAILABLE(10_5, 3_0); // evaluate a predicate against a set of objects and return a filtered set@end@interface NSMutableSet<ObjectType> (NSPredicateSupport)//根据谓词条件过滤集合,去掉集合中不符合条件的的元素- filterUsingPredicate:(NSPredicate *)predicate NS_AVAILABLE(10_5, 3_0); // evaluate a predicate against a set of objects and filter the mutable set directly@end

磋商操作

  • ANYSOME:钦赐下列表达式中的大肆成分。举个例子,ANY children.age < 18
  • ALL:钦点下列表明式中的全体因素。举例,ALL children.age < 18
  • NONE:钦命下列表达式中从未的因素。比方,NONE children.age < 18。它在逻辑上等于NOT
  • IN:等于SQL的IN操作,左侧的发挥必需现身在侧边钦定的汇集中。举例,name IN { 'Ben', 'Melissa', 'Nick' }

  • array[index]:指定数组中一定索引处的要素。

  • array[FIRST]:指定数组中的第三个因素。
  • array[LAST]:指定数组中的倒数成分。
  • array[SIZE]:指定数组的大小。
  • 亲自过问代码

布尔值谓词

  • TRUEPREDICATE:结果一贯为的谓词。
  • FALSEPREDICATE:结果平昔为的谓词。

咱俩见过&被用在谓词格式字符串中以创办理并答复合谓词。可是,大家也足以用NSCompoundPredicate来成功同样的做事。

诸如,下列谓词是相当的:

Objective-C

[NSCompoundPredicate andPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"age > 25"], [NSPredicate predicateWithFormat:@"firstName = %@", @"Quentin"]]];[NSPredicate predicateWithFormat:@"(age > 25) AND (firstName = %@)", @"Quentin"];

固然语法字符串文字更是便于输入,不过在有些时候,你必要整合现成的谓词。在这个情形下,你能够行使NSCompoundPredicate -andPredicateWithSubpredicates:&-orPredicateWithSubpredicates:

相同的,假若你在读过上周的篇章之后发掘你采用了太多的NSExpression的话,NSComparisonPredicate能够扶持您消除那几个难题。

就像NSCompoundPredicate一样,NSComparisonPredicate从子部件营造了二个NSPredicate--在这种情形下,侧边和右臂都是NSExpression
深入分析它的类的构造函数能够让大家一窥NSPredicate的格式字符串是如何剖析的:

Objective-C

+ (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类型

Objective-C

enum { NSLessThanPredicateOperatorType = 0, NSLessThanOrEqualToPredicateOperatorType, NSGreaterThanPredicateOperatorType, NSGreaterThanOrEqualToPredicateOperatorType, NSEqualToPredicateOperatorType, NSNotEqualToPredicateOperatorType, NSMatchesPredicateOperatorType, NSLikePredicateOperatorType, NSBeginsWithPredicateOperatorType, NSEndsWithPredicateOperatorType, NSInPredicateOperatorType, NSCustomSelectorPredicateOperatorType, NSContainsPredicateOperatorType, NSBetweenPredicateOperatorType};typedef NSUInteger NSPredicateOperatorType;
 NSArray * array = @[@"libai",@"dufu",@"sushi",@"dumu"]; NSPredicate * pred = [NSPredicate predicateWithFormat:@"SELF like %@",@"du*"]; NSArray * resultArr = [array filteredArrayUsingPredicate:pred]; NSLog(@"%@",resultArr);//输出值:( dufu, dumu) NSSet * set = [NSSet setWithObjects: [[ZZYPerson alloc]initWithName:@"li si" Age:@"25"], [[ZZYPerson alloc]initWithName:@"zhang san" Age:@"20"], [[ZZYPerson alloc]initWithName:@"wang wu" Age:@"18"],nil ]; NSPredicate * pred3 = [NSPredicate predicateWithFormat:@"name CONTAINS 'ang'"]; NSSet * resultSet = [set filteredSetUsingPredicate:pred3]; for (ZZYPerson * person in resultSet) { NSLog(@"%@",person.name); } NSArray * array3 = @[[[ZZYPerson alloc]initWithName:@"li si" Age:@"25"], [[ZZYPerson alloc]initWithName:@"zhang san" Age:@"20"], [[ZZYPerson alloc]initWithName:@"wang wu" Age:@"18"]]; NSArray * array4 = [array3 filteredArrayUsingPredicate:pred3]; for (ZZYPerson * person in array4) { NSLog(@"%@",person.name); }//输出值: zhang san wang wu

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”)以便在谓词格式字符串表达这一选项。

最后,假设您其实不甘于学习NSPredicate的格式语法,你也能够学习NSPredicate +predicateWithBlock:

Objective-C

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数据的提取需求。

本身知道自家已经说过很频繁了,不过NSPredicate真正是Cocoa的优势之一。别的语言的第三方库纵然能有它八分之四的手艺就曾经很幸运了--更别提标准库了。对于大家这一个使用和框架开荒者来讲,有它当做正式组件使得大家在管理多少时有了极大的优势。

NSExpression一样,NSPredicate直接在提示大家Foundation有多么好:它不但十二分有用,它精美的构架和规划也是大家写代码时灵感的发源。

作者Mattt Thompson

图片 1Mattt
Thompson

Mattt Thompson is the creator & maintainer of AFNetworking and other
popular open-source projects, including Postgres.app, ASCIIwwdc and
Nomad.

翻译者Zihan Xu

  • 由此采用占位符,在谓词表明式中使用变量
  • %K : 动态传入属性名
  • %@ : 动态设置属性值
  • $SUBSTSportage : 贰个动态变化的值,能够因而它动态改造比较标准

//设置NSPredict 中的可变参数,并计算结果- evaluateWithObject:(nullable id)object substitutionVariables:(nullable NSDictionary<NSString *, id> *)bindings NS_AVAILABLE(10_5, 3_0); // single pass evaluation substituting variables from the bindings dictionary for any variable expressions encountered//设置NSPredict 的可变参数,返回一个NSPredict 对象- (instancetype)predicateWithSubstitutionVariables:(NSDictionary<NSString *, id> *)variables; // substitute constant values for variables
  • 示范代码

 ZZYPerson * person1 = [[ZZYPerson alloc]initWithName:@"zhang san" Age:@"21"]; ZZYPerson * person2 = [[ZZYPerson alloc]initWithName:@"li si" Age:@"25"];ZZYPerson * person3 = [[ZZYPerson alloc]initWithName:@"stark" Age:@"11"]; ZZYPerson * person4 = [[ZZYPerson alloc]initWithName:@"sunny" Age:@"30"]; NSArray * array2 = @[person1,person2,person3,person4]; NSString * name = @"age"; NSString * age = @"3"; NSPredicate * changePre1 = [NSPredicate predicateWithFormat:@"%K CONTAINS[cd] %@",name,age]; NSArray * newArray2 = [array2 filteredArrayUsingPredicate:changePre1]; for (ZZYPerson * person in newArray2) { NSLog(@"newArray2%@----%@",person.name,person.age); } //name中包含$SUBSTR的字串 NSPredicate * changePre2 = [NSPredicate predicateWithFormat:@"%K CONTAINS[cd] $SUBSTR",@"name"]; //指定$SUBSTR的值为sun NSPredicate * newChangePre2 = [changePre2 predicateWithSubstitutionVariables:@{@"SUBSTR":@"sun"}]; NSArray * newArray3 = [array2 filteredArrayUsingPredicate:newChangePre2]; for (ZZYPerson * person in newArray3) { NSLog(@"newArray3%@----%@",person.name,person.age); } NSPredicate * newChangePre3 = [changePre2 predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:@"ang",@"SUBSTR", nil]]; NSArray * newArray4 = [array2 filteredArrayUsingPredicate:newChangePre3]; for (ZZYPerson * person in newArray4) { NSLog(@"newArray4%@----%@",person.name,person.age); }//输出结果:2016-06-27 23:07:11.820 ZZYNSPredicate[4540:96427] newArray2sunny----302016-06-27 23:07:11.820 ZZYNSPredicate[4540:96427] newArray3sunny----302016-06-27 23:07:11.820 ZZYNSPredicate[4540:96427] newArray4zhang san----21

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图