新的博客地址

@[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;


    iOS逆向
    44 声望15 粉丝