新的博客地址
@[toc]
前言
谓词(NSPredicate)是Objective-C中针对数据集合的一种逻辑筛选条件,它类似于数据库中SQL语句对数据筛选的限制约束条件。
Objective-C中的谓词经常用来从数组(Array)、集合(Set)等数据集合中筛选数据元素,谓词约束条件封装在NSPredicate对象中,可通过类函数predicateWithFormat和逻辑约束语句进行初始化
- 在进行一些数据的筛选的时候经常使用到它:
例如: CoreData的数据查询、按照特定条件(日期)排序的数据、从数组进行数据查询等等。
- 格式化字符串可以被看作三部分:左手表达式、逻辑符号和右手表达式。
其中,左手表达式是一个对象的属性键值(键路径);逻辑符号是一个基本的逻辑运算符;右手表达式是约束范围。
逻辑运算符还有很多,它们与SQL语句中的语法基本相对应,除了最基本的逻辑运算符:>、==、<=、&&等之外,还有逻辑词IN、CONTAINS、like等。它们的使用情况如下:
I、例子
谓词技术的使用 NSPredicate (以一定的条件(特定日期)过滤maTemp数组,即进行大数据搜索。)
1.0 获取选中的规格ID
- isSelected
- (NSString *)SpecValIds{
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"isSelected == %d",YES];
NSMutableArray *tmparr = [self.platProductAttributeAndSpecificationDto.ProductSpecificationDtos filteredArrayUsingPredicate:predicate];
NSArray *editReturnedModeltmparr = [tmparr valueForKeyPath:@"@distinctUnionOfObjects.id"];//
// NSString iOS 将数组中的元素用符号拼接字符串的方法
NSString *string = [editReturnedModeltmparr componentsJoinedByString:@","];
return string;
}
1.1将含有日期属性的对象数组中,进行按照日期重新进行分组
使用谓词进行数据分组 (数组元素为 自定义类型)
//2.按照日期进行分组展示
// 重新按照日期进行分组组织数据
// 找出不重复的日期
/**
对象操作:
针对数组的情况
@distinctUnionOfObjects:返回指定属性去重后的值的数组
@unionOfObjects:返回指定属性的值的数组,不去重
属性的值不能为空,否则产生异常。
*/
//1)取出日期分组
NSArray *arDistinct = [maTemp valueForKeyPath:@"@distinctUnionOfObjects.strDateCreated"];//maTemp是一些含有日期属性的对象集合
//2)构建排序规则NSComparator
NSComparator cmptr = ^(id obj1, id obj2){
NSString *strData1 = obj1;
NSString *strData2 = obj2;
NSComparisonResult ret = [strData1 compare:strData2];
return ret;
};
// 3)按数字从小到大进行排序(将最新的数据显示在前面)
NSArray *arSorted = [arDistinct sortedArrayUsingComparator:cmptr];
arSorted = arSorted.reverseObjectEnumerator.allObjects;//顺序取反
NSPredicate *predicate = nil;
// 4)按照日期进行分组
for (NSString *strDateCreated in arSorted)
{
predicate = [NSPredicate predicateWithFormat:@"strDateCreated == %@", strDateCreated];
NSArray *arFiltered = [maTemp filteredArrayUsingPredicate:predicate];//以一定的条件(特定日期)过滤maTemp数组,即进行大数据搜索。
OrderQueryGroupData *data = [OrderQueryGroupData alloc];
data.strDateCreated = strDateCreated;
data.maOrderData = [NSMutableArray arrayWithArray:arFiltered];
data.maOrderDataF = [IPOrderDataFrame frameListWith:data.maOrderData];
[self.maOrderQuery addObject:data];
}
1.2 示例: 数据的过滤,城市搜索
城市搜索
*/
//方式二: 谓词技术的使用
searchText = searchText.uppercaseString;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@" pinYinHead.uppercaseString contains %@ or name.uppercaseString contains %@ or pinYin.uppercaseString contains %@ ",searchText,searchText,searchText];
return [_cityModels filteredArrayUsingPredicate:predicate];
}
//方式一。
+ (NSArray *)searchcityModelsWithSeatchText:(NSString *)searchText{
NSMutableArray *array = [NSMutableArray array];
searchText = [searchText uppercaseString];
for (DKCityModel *obj in _cityModels) {
if ([obj.name.uppercaseString containsString:searchText] || [obj.pinYin.uppercaseString containsString:searchText] || [obj.pinYinHead.uppercaseString containsString:searchText]) {
[array addObject:obj];
}
}
return array;
}
1.3 示例:银行列表的过滤
- 多个过滤条件的拼接
#pragma mark - ******** //列表的银行过滤
- (void)predicateBankList{
if ([Session Instance].arrOnlySupportBankList.count == 0) {
return;
}
NSMutableString *stringpredicate = [NSMutableString string] ;
// for (NSString *code in ) {
// if ([code isEqualToString:[Session Instance].arrOnlySupportBankList[0]]) {
// [stringpredicate appendFormat:@" strBankNO == %@ ",code];
// }else {
// [stringpredicate appendFormat:@" strBankNO == %@ ",code];
// }
// }
NSInteger count = [Session Instance].arrOnlySupportBankList.count;
for (int i = 0; i<count;i++) {
if (count == 1) {
[stringpredicate appendFormat:@" strBankNO == '%@' ",[Session Instance].arrOnlySupportBankList[i]];
}else if (count>1){
if (i == 0) {
[stringpredicate appendFormat:@" strBankNO == '%@' ",[Session Instance].arrOnlySupportBankList[i]];
}else{
[stringpredicate appendFormat:@"or strBankNO == '%@' ",[Session Instance].arrOnlySupportBankList[i]];
}
}
}
if ([stringpredicate isEqualToString:@"" ] ) {
return;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:stringpredicate];
self.bankListDepositCard = [NSMutableArray arrayWithArray:[ self.bankListDepositCard filteredArrayUsingPredicate:predicate]];
self.bankListCreditCard = [NSMutableArray arrayWithArray:[ self.bankListCreditCard filteredArrayUsingPredicate:predicate]];
}
1.4: 字符串数组的过滤(数组元素为系统的自有类型)**
- 字符串数组的过滤
/**
BankInfoData 对象的 的银行卡编号是否包含在 arrOnlySupportBankList 银行卡编号数组中
@return bool
*/
- (BOOL)isaBankSelectedEqualToBusinessBank:(KNData*)data{
NSArray *arrOnlySupportBankList= [KNSession Instance].arrOnlySupportBankList;//kevin
NSArray *tmp = [NSArray array];
NSString *stringpredicate = [NSString stringWithFormat:@" self == '%@'",data.strBankNO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:stringpredicate];
tmp = [NSMutableArray arrayWithArray:[ arrOnlySupportBankList filteredArrayUsingPredicate:predicate]];
if (tmp.count>0) {
return YES;
}else{
return NO;
}
}
1.5: Core Data的数据查询
- 例子:保存未读消息
#pragma mark - 保存未读消息
/** 先查询,在修改 */
+ (void)saveMessageWithMessage:(IPMessageDetailData*)data{
if (data.messageId == nil || data == nil){
return;
}
NSManagedObjectContext *context = [IPMessageDataTool shareContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"KNMessage" inManagedObjectContext:context];
// 设置排序(按照messageId降序)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"messageId" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:sort];
// 设置条件过滤(搜索name中包含字符串"Itcast-1"的记录,注意:设置条件过滤时,数据库SQL语句中的%要用*来代替,所以%Itcast-1%应该写成*Itcast-1*)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"messageId = %@ AND operateID = %@",data.messageId,[SessionMgr Instance].operateID];
request.predicate = predicate;
// 执行请求
// request.fetchLimit = 50;
NSError *error = nil;
NSArray *objs = [context executeFetchRequest:request error:&error];
if (error) {
[NSException raise:@"查询错误" format:@"%@", [error localizedDescription]];
}
Message *tmpMessage;
if (objs.count>0) {
tmpMessage = objs[0];
return;
}else{
tmpMessage = [NSEntityDescription insertNewObjectForEntityForName:@"Message" inManagedObjectContext:context];
}
tmpMessage.messageExpiredTime = data.messageExpiredTime;
tmpMessage.messageIssueTime = data.messageIssueTime;
tmpMessage.messageId = data.messageId;
tmpMessage.messageTitle = data.messageTitle;
tmpMessage.operateID = [SessionMgr Instance].operateID;
tmpMessage.isRead = NO;
BOOL success = [context save:&error];
if (!success) {
[NSException raise:@"访问数据库错误" format:@"%@", [error localizedDescription]];
}
}
1.6 使用谓词进行数据分组 (数组元素为 自定义类型)
1.6.1 过滤 Style 查找数据
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"Style == %@", [[NSNumber numberWithInteger:type] description]];
NSArray *arFiltered = [ model.List filteredArrayUsingPredicate:predicate];//以一定的条件(特定日期)过滤maTemp数组,即进行大数据搜索。
model.List = [NSMutableArray arrayWithArray:arFiltered];
return model;
1.6.2 过滤type 查找电子签名的数据
- 查找电子签名的数据【避免遍历数组 certificateInfoList,判断type=8】
- (CRMcertificateInfoListDto *)getSignimgURLCRMcertificateInfoListDto{
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"type == %@", [[NSNumber numberWithInteger:CRMcertificateInfoListDtotype4Sign] description]];
NSArray *arFiltered = [ self.certificateInfoList filteredArrayUsingPredicate:predicate];//以一定的条件(特定日期)过滤maTemp数组,即进行大数据搜索。
CRMcertificateInfoListDto *dto = nil;
if(arFiltered.count>0){
dto = arFiltered.firstObject;
}
return dto;
}
II、常用正则表达式
利用NSPredicate 的evaluateWithObject 方法进行校验
#pragma 正则匹配手机号
+ (BOOL)checkTelNumber:(NSString *) telNumber
{
NSString *pattern = @^1+[3578]+\d{9};
NSPredicate *pred = [NSPredicate predicateWithFormat:@SELF MATCHES %@, pattern];
BOOL isMatch = [pred evaluateWithObject:telNumber];
return isMatch;
}
#pragma 正则匹配用户密码6-18位数字和字母组合
+ (BOOL)checkPassword:(NSString *) password
{
NSString *pattern = @^(?![0-9]+$)(?![a-zA-Z]+$)[a-zA-Z0-9]{6,18};
NSPredicate *pred = [NSPredicate predicateWithFormat:@SELF MATCHES %@, pattern];
BOOL isMatch = [pred evaluateWithObject:password];
return isMatch;
}
#pragma 正则匹配用户姓名,20位的中文或英文
+ (BOOL)checkUserName : (NSString *) userName
{
NSString *pattern = @^[a-zA-Z一-龥]{1,20};
NSPredicate *pred = [NSPredicate predicateWithFormat:@SELF MATCHES %@, pattern];
BOOL isMatch = [pred evaluateWithObject:userName];
return isMatch;
}
#pragma 正则匹配用户身份证号15或18位
+ (BOOL)checkUserIdCard: (NSString *) idCard
{
NSString *pattern = @(^[0-9]{15}$)|([0-9]{17}([0-9]|X)$);
NSPredicate *pred = [NSPredicate predicateWithFormat:@SELF MATCHES %@, pattern];
BOOL isMatch = [pred evaluateWithObject:idCard];
return isMatch;
}
#pragma 正则匹员工号,12位的数字
+ (BOOL)checkEmployeeNumber : (NSString *) number
{
NSString *pattern = @^[0-9]{12};
NSPredicate *pred = [NSPredicate predicateWithFormat:@SELF MATCHES %@, pattern];
BOOL isMatch = [pred evaluateWithObject:number];
return isMatch;
}
#pragma 正则匹配URL
+ (BOOL)checkURL : (NSString *) url
{
NSString *pattern = @^[0-9A-Za-z]{1,50};
NSPredicate *pred = [NSPredicate predicateWithFormat:@SELF MATCHES %@, pattern];
BOOL isMatch = [pred evaluateWithObject:url];
return isMatch;
}
III、 避免循环遍历数组的其他案例
3.1 使用makeObjectsPerformSelector 来避免循环遍历数组
- 使用makeObjectsPerformSelector 设置self.StorePayFeeRateListDto.payFeeRateList数组内部元素的属性settlementCycle (结算周期:0-T0 1-T1 默认0) 来避免循环便利数组
[self.StorePayFeeRateListDto.payFeeRateList makeObjectsPerformSelector:@selector(setSettlementCycle:) withObject:swichStr];
- 旧的代码:循环遍历数组
for (int i = 0; i < self.StorePayFeeRateListDto.payFeeRateList.count; i++) {//settlementCycle
NSMutableDictionary * mutDic = [[NSMutableDictionary alloc]initWithDictionary:_sectionArr[i]];
[mutDic setObject:swichStr forKey:@"settlementCycle"];
[_sectionArr setObject:mutDic atIndexedSubscript:i];
}
3.2 使用enumerate开头的方法
[objc] view plain copy
/* In the enumerate methods, the blocks will be invoked inside an autorelease pool, so any values assigned inside the block should be retained.
*/
- (void)enumerateSubstringsInRange:(NSRange)range options:(NSStringEnumerationOptions)opts usingBlock:(void (^)(NSString * __nullable substring, NSRange substringRange, NSRange enclosingRange, BOOLBOOL *stop))block NS_AVAILABLE(10_6, 4_0);
- (void)enumerateLinesUsingBlock:(void (^)(NSString *line, BOOLBOOL *stop))block NS_AVAILABLE(10_6, 4_0);
- 用来一行一行的读取一个txt文档的内容
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"girl" ofType:@"txt"];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
NSString *fileStr = [[NSString alloc]initWithData:fileData encoding:NSUTF8StringEncoding];
//一行一行的读取
[fileStr enumerateLinesUsingBlock:^(NSString * _Nonnull line, BOOLBOOL * _Nonnull stop) {
NSLog(@"%@\n",line);
}];
// 一个字符一字符的读取
[fileStr enumerateSubstringsInRange:NSMakeRange(0, fileStr.length) options:NSStringEnumerationByWords usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOLBOOL * _Nonnull stop) {
NSLog(@"tmp111===%@",substring);
}];
- 遍历支付密码的例子
// 一个字符一字符的读取
[fileStr enumerateSubstringsInRange:NSMakeRange(0, fileStr.length) options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
NSLog(@"tmp111===%@",substring);
[m_textField appendPsw:substring];
[_pswView SetInputNum:_inputEncData.count];
[m_textField onChange];
}];
- NSStringEnumerationByWords
[fileStr enumerateSubstringsInRange:NSMakeRange(0, fileStr.length) options:NSStringEnumerationByWords
usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
NSLog(@"tmp111===%@",substring);
[m_textField appendPsw:substring];
[_pswView SetInputNum:_inputEncData.count];
[m_textField onChange];
}];
see also
- OC中的 BOOL不如bool好用
BOOL表示 1是YES , 所以非1是NO. 而bool表示0是false,所以非0是true;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。