当前位置: 移动技术网 > IT编程>移动开发>IOS > 30分钟快速带你理解iOS中的谓词NSPredicate

30分钟快速带你理解iOS中的谓词NSPredicate

2019年07月24日  | 移动技术网IT编程  | 我要评论

全国公务员考试时间,射击双保险出局,再次微笑吻戏

一、引言

在现代汉语的解释中,谓词是用来描述或判断客体性质、特征或者客体之间关系的词项。通俗的说,它是描述事物属性的。在ios开发cocoa框架中,有提供nspredicate类,这个类通常也被成为谓词类,其主要的作用是在cocoa中帮助查询和检索,但是需要注意,实质上谓词并不是提供查询和检索的支持,它是一种描述查询检索条件的方式,就像更加标准通用的正则表达式一样。

nspredicate提供的谓词可以分为两类:比较谓词和复合谓词。

  • 比较谓词:比较谓词通过使用比较运算符来描述所符合条件的属性状态。
  • 复合谓词:复合谓词用来组合多个比较谓词的结果,取交集,并集或补集。

对于比较谓词,可以描述精准的比较也可以通过范围或者包含等进行模糊比较。需要注意,任何cocoa类对象都可以支持谓词,但是此类需要实现键值编码(key-value-coding)协议。

二、nspredicate类的应用解析

nspredicate提供创建谓词对象和解析谓词对象的方法,它也是cocoa中有关谓词的类中的基类。我们在日常开发中,nspredicate类的应用频率也最高。

创建谓词对象有3种方式,分别是通过格式化字符串创建谓词,直接通过代码创建谓词,通过模板创建谓词。nspredicate提供了如下函数来进行初始化:

//通过格式化字符串来进行谓词对象的初始化
+ (nspredicate *)predicatewithformat:(nsstring *)predicateformat argumentarray:(nullable nsarray *)arguments;
+ (nspredicate *)predicatewithformat:(nsstring *)predicateformat, ...;
+ (nspredicate *)predicatewithformat:(nsstring *)predicateformat arguments:(va_list)arglist;

使用格式化字符串进行谓词的初始化十分灵活,但是需要注意,其谓词字符串的语法和正则表达式并不一样,后面会有具体的介绍,下面是一个谓词检索示例:

 //检索属性length为5的对象
 nspredicate * predicate = [nspredicate predicatewithformat:@"length = 5"];
 //对于这个数组中的字符串,即是检索字符串长度为5的元素
 nsarray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
 nsarray * result = [test filteredarrayusingpredicate:predicate];
 //将打印@[@"swfas"]
 nslog(@"%@",result);

其实,你也可以像使用nslog函数一样来进行格式化字符串的构造,可以使用%@,%d等等格式化字符来在运行时替换为变量的实际值。同时也需要注意,这种格式化字符串创建的谓词语句并不会进行语法检查,错误的语法会产生运行时错误,要格外小心。有一个小细节需要注意,在进行格式化时,如果使用的是变量则不需要添加引号,解析器会帮助你添加,如果使用到常量,则要用转义字符进行转义,例如:

nspredicate * predicate = [nspredicate predicatewithformat:@"name = %@ && age = \"25\"",name];

对于属性名,如果也需要进行格式化,需要注意不能使用%@符号,这个符号在解析时会被解析器自动添加上引号,可以使用%k,示例如下:

 nsstring * key = @"length";
 nspredicate * predicate = [nspredicate predicatewithformat:@"%k = 5",key];
 nsarray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
 nsarray * result = [test filteredarrayusingpredicate:predicate];
 //将打印@[@"swfas"]
 nslog(@"%@",result);

通过模板来创建谓词对象也是一种十分常用的方式,和格式化字符串不同的是,谓词模板中只有键名,没有键值,键值需要在字典中进行提供,例如:

 nspredicate * predicate = [nspredicate predicatewithformat:@"length = $length"];
 predicate = [predicate predicatewithsubstitutionvariables:@{@"length":@5}];
 nsarray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
 nsarray * result = [test filteredarrayusingpredicate:predicate];
 //将打印@[@"swfas"]
 nslog(@"%@",result);

nspredicate中其他属性与方法解析如下:

//创建一个总是验证通过(yes)或不通过(no)的谓词对象
/*
如果创建的是验证通过的,则任何检索都会成功进行返回,否则任何检索都会失败不返回任何对象
*/
+ (nspredicate *)predicatewithvalue:(bool)value;
//自定义实现检索函数
/*

例如前面的示例也可以这样写

nspredicate * predicate = [nspredicate predicatewithblock:^bool(id _nullable evaluatedobject, nsdictionary<nsstring *,id> * _nullable bindings) {
 if ([evaluatedobject length]==5) {
 return yes;
 }
 return no;
 }];
*/
+ (nspredicate*)predicatewithblock:(bool (^)(id _nullable evaluatedobject, nsdictionary<nsstring *, id> * _nullable bindings))block;
//格式化字符串属性
@property (readonly, copy) nsstring *predicateformat; 
//当使用谓词模板来进行对象创建时,这个函数用来设置谓词模板中变量替换
- (instancetype)predicatewithsubstitutionvariables:(nsdictionary<nsstring *, id> *)variables;
//检查一个object对象是否可以通过验证
- (bool)evaluatewithobject:(nullable id)object; 
//用谓词模板进行对象的验证
- (bool)evaluatewithobject:(nullable id)object substitutionvariables:(nullable nsdictionary<nsstring *, id> *)bindings;

三、通过代码来创建谓词对象

前面我们说有3种创建谓词对象的方式,有两种我们已经有介绍,通过代码直接创建谓词对象是最复杂的一种。通过代码来创建谓词对象十分类似通过代码来创建autolayout约束。通过前面我们的介绍,谓词实际是用表达式来验证对象,用代码来创建谓词实际就是用代码来创建表达式。

1.先来看nscomparisonpredicate类

这个类是nspredicate的子类,其用来创建比较类型的谓词。例如使用下面的代码来改写上面的例子:

 //创建左侧表达式对象 对应为键
 nsexpression * left = [nsexpression expressionforkeypath:@"length"];
 //创建右侧表达式对象 对应为值
 nsexpression * right = [nsexpression expressionforconstantvalue:[nsnumber numberwithint:5]];
 //创建比较谓词对象 这里设置为严格等于
 nscomparisonpredicate * pre = [nscomparisonpredicate predicatewithleftexpression:left rightexpression:right modifier:nsdirectpredicatemodifier type:nsequaltopredicateoperatortype options:nscaseinsensitivepredicateoption];
 nsarray * test = @[@"sda",@"321",@"sf12",@"dsdwq1",@"swfas"];
 nsarray * result = [test filteredarrayusingpredicate:pre];
 //将打印@[@"swfas"]
 nslog(@"%@",result);

nscomparisonpredicatemodifier用来进行条件的修饰设置,枚举如下:

typedef ns_enum(nsuinteger, nscomparisonpredicatemodifier) {
 nsdirectpredicatemodifier = 0, //直接进行比较操作
 nsallpredicatemodifier, //用于数组或集合 只有当内部所有元素都通过验证时 集合才算通过
 nsanypredicatemodifier //同于数组或集合 当内部有一个元素满足时 集合算通过验证
};

关于nsallpredicatemodifier和nsanypredicatemodifier,这两个枚举专门用于数组或集合类型对象的验证,all会验证其中所有元素,全部通过后数组或集合才算验证通过,any则只要有一个元素验证通过,数组或集合就算验证通过,例如:

 nspredicate * pre = [nspredicate predicatewithformat:@"all length = 5"];
 nsarray * test = @[@[@"aaa",@"aa"],@[@"bbbb",@"bbbbb"],@[@"ccccc",@"ccccc"]];
 nsarray * result = [test filteredarrayusingpredicate:pre];
 //将打印@[@[@"ccccc",@"ccccc"]]
 nslog(@"%@",result);

nspredicateoperatortype枚举用来设置运算符类型,如下:

typedef ns_enum(nsuinteger, nspredicateoperatortype) {
 nslessthanpredicateoperatortype = 0, // 小于
 nslessthanorequaltopredicateoperatortype, // 小于等于
 nsgreaterthanpredicateoperatortype, // 大于
 nsgreaterthanorequaltopredicateoperatortype, // 大于等于
 nsequaltopredicateoperatortype, // 等于
 nsnotequaltopredicateoperatortype, //不等于
 nsmatchespredicateoperatortype, //正则比配
 nslikepredicateoperatortype, //like匹配 与sql类似
 nsbeginswithpredicateoperatortype, //左边的表达式 以右边的表达式作为开头
 nsendswithpredicateoperatortype,//左边的表达式 以右边的表达式作为结尾
 nsinpredicateoperatortype, // 左边的表达式 出现在右边的集合中 
 nscustomselectorpredicateoperatortype,//使用自定义的函数来进行 验证
 nscontainspredicateoperatortype, //左边的集合包括右边的元素
 nsbetweenpredicateoperatortype //左边表达式的值在右边的范围中 例如 1 between { 0 , 33 }
};

nscomparisonpredicateoptions枚举用来设置比较的方式,如下:

//如果不需要特殊指定 这个枚举值也可以传0
typedef ns_options(nsuinteger, nscomparisonpredicateoptions) {
 nscaseinsensitivepredicateoption = 0x01, //不区分大小写
 nsdiacriticinsensitivepredicateoption = 0x02,//不区分读音符号
 nsnormalizedpredicateoption //比较前进行预处理 代替上面两个选项
};

2.nsexpression类

nsexpression类则是提供创建表达式,下面列出了其中一些方便理解的方法:

//通过格式化字符串创建表达式
+ (nsexpression *)expressionwithformat:(nsstring *)expressionformat argumentarray:(nsarray *)arguments;
+ (nsexpression *)expressionwithformat:(nsstring *)expressionformat, ...;
+ (nsexpression *)expressionwithformat:(nsstring *)expressionformat arguments:(va_list)arglist;
//直接通过对象创建常亮的表达式
+ (nsexpression *)expressionforconstantvalue:(nullable id)obj; 
//创建变量表达式 验证时将从binding字典中进行替换
+ (nsexpression *)expressionforvariable:(nsstring *)string; 
//将多个表达式组合成一个
+ (nsexpression *)expressionforaggregate:(nsarray<nsexpression *> *)subexpressions;
+ (nsexpression *)expressionforunionset:(nsexpression *)left with:(nsexpression *)right;
+ (nsexpression *)expressionforintersectset:(nsexpression *)left with:(nsexpression *)right;
+ (nsexpression *)expressionforminusset:(nsexpression *)left with:(nsexpression *)right;
+ (nsexpression *)expressionforsubquery:(nsexpression *)expression usingiteratorvariable:(nsstring *)variable predicate:(nspredicate *)predicate;
//通过预定义的函数和参数数组来构建表达式对象 预定义的函数 可见dev开发文档
+ (nsexpression *)expressionforfunction:(nsstring *)name arguments:(nsarray *)parameters;

3.nscompoundpredicate类

这个类也是nspredicate类的子类,其使用逻辑关系来组合多个谓词对象,解析如下:

//进行对象初始化
/*
typedef ns_enum(nsuinteger, nscompoundpredicatetype) {
 nsnotpredicatetype = 0, //取非
 nsandpredicatetype, //与运算 
 nsorpredicatetype, //或运算
};
*/
- (instancetype)initwithtype:(nscompoundpredicatetype)type subpredicates:(nsarray<nspredicate *> *)subpredicates;
//快速创建与运算
+ (nscompoundpredicate *)andpredicatewithsubpredicates:(nsarray<nspredicate *> *)subpredicates;
//快速创建或运算
+ (nscompoundpredicate *)orpredicatewithsubpredicates:(nsarray<nspredicate *> *)subpredicates;
//快速创建非运算
+ (nscompoundpredicate *)notpredicatewithsubpredicate:(nspredicate *)predicate;

四、谓词的几种使用场景

谓词主要用在验证对象,数组和集合的过滤。对象的验证前面有介绍,关于数据和集合的过滤函数,类别如下:

@interface nsarray<objecttype> (nspredicatesupport)
//不可变数组使用过滤器后返回新数组
- (nsarray<objecttype> *)filteredarrayusingpredicate:(nspredicate *)predicate; 
@end
@interface nsmutablearray<objecttype> (nspredicatesupport)
//可变数组可以直接进行过滤操作
- (void)filterusingpredicate:(nspredicate *)predicate;
@end
@interface nsset<objecttype> (nspredicatesupport)
//不可变集合过滤后返回新集合
- (nsset<objecttype> *)filteredsetusingpredicate:(nspredicate *)predicate;
@end
@interface nsmutableset<objecttype> (nspredicatesupport)
//可变集合可以直接进行过滤操作
- (void)filterusingpredicate:(nspredicate *)predicate;
@end
@interface nsorderedset<objecttype> (nspredicatesupport)
- (nsorderedset<objecttype> *)filteredorderedsetusingpredicate:(nspredicate *)p;
@end
@interface nsmutableorderedset<objecttype> (nspredicatesupport)
- (void)filterusingpredicate:(nspredicate *)p;
@end

五、谓词的格式化语法总览

下面列出了在谓词的格式化字符串规则语法。

语法规则 意义
= 左侧等于右侧
==     左侧等于右侧,与=一致 
>=     左侧大于等于右侧
=> 左侧大于等于右侧 与 >=一致
<= 左侧小于等于右侧
=<     左侧小于等于右侧 与<=一致
> 左侧大于右侧
< 左侧小于右侧
!= 左侧不等于右侧
<> 左侧不等于右侧 与!=一致
between    左侧在右侧的集合中 key between @[@1,@2]
truepredicate 总是返回yes的谓词
falsepredicate 总是返回no的谓词
and 逻辑与
&& 逻辑与 与and一致
or 逻辑或
|| 逻辑或 与or一致
not 逻辑非
!     逻辑非 与not一致
beginwith 左侧以右侧字符串开头
endwith 左侧以右侧字符串结尾
contains 左侧集合包含右侧元素
like     左侧等于右侧 并且 *和?等通配符可以使用
matches 正则匹配
any 对于数组集合类,验证其中任一元素
some 同any一致
all 对于数组集合类,验证其中所有元素
none 作用等同于not (any)
in     左侧在右侧集合中
self 被验证的对象本身

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

  • ios uicollectionview实现横向滚动

    现在使用卡片效果的app很多,之前公司让实现一种卡片效果,就写了一篇关于实现卡片的文章。文章最后附有demo实现上我选择了使用uicollectionview ... [阅读全文]
  • iOS UICollectionView实现横向滑动

    本文实例为大家分享了ios uicollectionview实现横向滑动的具体代码,供大家参考,具体内容如下uicollectionview的横向滚动,目前我使... [阅读全文]
  • iOS13适配深色模式(Dark Mode)的实现

    iOS13适配深色模式(Dark Mode)的实现

    好像大概也许是一年前, mac os系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的终于, 随着iphone11等新手机的发售, ios 13系统... [阅读全文]
  • ios 使用xcode11 新建项目工程的步骤详解

    ios 使用xcode11 新建项目工程的步骤详解

    xcode11新建项目工程,新增了scenedelegate这个类,转而将原appdelegate负责的对ui生命周期的处理担子接了过来。故此可以理解为:ios... [阅读全文]
  • iOS实现转盘效果

    本文实例为大家分享了ios实现转盘效果的具体代码,供大家参考,具体内容如下demo下载地址: ios转盘效果功能:实现了常用的ios转盘效果,轮盘抽奖效果的实现... [阅读全文]
  • iOS开发实现转盘功能

    本文实例为大家分享了ios实现转盘功能的具体代码,供大家参考,具体内容如下今天给同学们讲解一下一个转盘选号的功能,直接上代码直接看viewcontroller#... [阅读全文]
  • iOS实现轮盘动态效果

    本文实例为大家分享了ios实现轮盘动态效果的具体代码,供大家参考,具体内容如下一个常用的绘图,主要用来打分之类的动画,效果如下。主要是ios的绘图和动画,本来想... [阅读全文]
  • iOS实现九宫格连线手势解锁

    本文实例为大家分享了ios实现九宫格连线手势解锁的具体代码,供大家参考,具体内容如下demo下载地址:效果图:核心代码://// clockview.m// 手... [阅读全文]
  • iOS实现卡片堆叠效果

    本文实例为大家分享了ios实现卡片堆叠效果的具体代码,供大家参考,具体内容如下如图,这就是最终效果。去年安卓5.0发布的时候,当我看到安卓全新的material... [阅读全文]
  • iOS利用余弦函数实现卡片浏览工具

    iOS利用余弦函数实现卡片浏览工具

    本文实例为大家分享了ios利用余弦函数实现卡片浏览工具的具体代码,供大家参考,具体内容如下一、实现效果通过拖拽屏幕实现卡片移动,左右两侧的卡片随着拖动变小,中间... [阅读全文]
验证码:
移动技术网