zoukankan      html  css  js  c++  java
  • iOS中的谓词NSPredicate的使用

      今天写一篇关于iOS中关于谓词一些用法,我们先来看苹果官方给出的解释:

      

      The NSPredicate class is used to define logical conditions used to constrain a search either for a fetch or for in-memory filtering.

      You use predicates to represent logical conditions, used for describing objects in persistent stores and in-memory filtering of objects. Although it is common to create predicates directly from instances of NSComparisonPredicate, NSCompoundPredicate, and NSExpression, you often create predicates from a format string which is parsed by the class methods on NSPredicate. Examples of predicate format strings include:

    • Simple comparisons, such as grade == "7" or firstName like "Shaffiq"
    • Case and diacritic insensitive lookups, such as name contains[cd] "itroen"
    • Logical operations, such as (firstName like "Mark") OR (lastName like "Adderley")
    • In OS X v10.5 and later, you can create €œbetween€ predicates such as date between {$YESTERDAY, $TOMORROW}.

    You can create predicates for relationships, such as:

    • group.name like "work*"
    • ALL children.age > 12
    • ANY children.age > 12

      You can create predicates for operations, such as @sum.items.price < 1000. For a complete syntax reference, refer to the Predicate Programming Guide.

      You can also create predicates that include variables, so that the predicate can be pre-defined before substituting concrete values at runtime. In OS X v10.4, for predicates that use variables, evaluation is a two step process (see predicateWithSubstitutionVariables: and evaluateWithObject:). In OS X v10.5 and later, you can use evaluateWithObject:substitutionVariables:, which combines these steps.

       定义一个谓词的用途是通过定义一个逻辑的条件来过滤信息。

       下面我们来通过代码的方式来看一些谓词的使用。

       下面我们通过定义一个汽车的类来了解谓词。

       汽车类car的头文件定义如下: 

    #import <Foundation/Foundation.h>
    
    @class Engine;
    @class Tire;
    
    @interface Car : NSObject
    
    @property (nonatomic, copy) Engine *engine;
    @property (nonatomic, copy) NSMutableArray *tires;
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) NSString *make;//制造厂商
    @property (nonatomic, copy) NSString *model;
    @property (nonatomic, assign) int modelYear;
    @property (nonatomic, assign) int numberOfDoors;
    @property (nonatomic, assign) float mileage;
    
    - (void)setTire:(Tire*)tire atIndex:(int)index;
    @end

       轮胎类头文件定义:

    #import <Foundation/Foundation.h>
    
    @interface Engine : NSObject<NSCopying>
    
    @property (nonatomic, assign) NSInteger horsepower;//马力
    @end

      车库类头文件的定义:

    #import <Cocoa/Cocoa.h>
    @class Car;
    @interface Garage : NSObject
    {
        NSString *name;
        NSMutableArray *cars;
    }
    @property (readwrite, copy) NSString *name;
    @property (nonatomic, copy) NSMutableArray *cars;
    - (void) addCar: (Car *) car;
    - (void) print;
    @end // Garage

      轮胎类头文件的定义:

    #import <Foundation/Foundation.h>
    
    @interface Tire : NSObject
    
    @end

     

      下面是mian函数中的一些初始化的一些定义:

    #import <Foundation/Foundation.h>
    
    #import "Car.h"
    #import "Tire.h"
    #import "Engine.h"
    #import "Garage.h"
    
    //下面的方法的作用是重新构造一辆汽车 Car
    *makeCar (NSString *name, NSString *make, NSString *model, int modelYear, int numberOfDoors,float mileage, int horsepower) { Car *car = [[[Car alloc] init] autorelease]; car.name = name; car.make = make; car.model = model; car.modelYear = modelYear; car.numberOfDoors = numberOfDoors; car.mileage = mileage; Engine *engine = [[[Engine alloc] init] autorelease]; [engine setValue: [NSNumber numberWithInt: horsepower] forKey: @"horsepower"]; car.engine = engine; // Make some tires. for (int i = 0; i < 4; i++) { Tire * tire= [[[Tire alloc] init] autorelease]; [car setTire: tire atIndex: i]; } return (car); } // makeCar

    //接下来在mian函数中定义一个车库和里面存放的汽车 int main(int argc, const char * argv[]) { Garage *garage = [[Garage alloc] init]; garage.name = @"Joe’s Garage"; Car *car; car = makeCar (@"Herbie", @"Honda", @"CRX", 1984, 2, 110000, 58); [garage addCar: car];
      

       car = makeCar (@"Badger", @"Acura", @"Integra", 1987, 5, 217036.7, 130);

       [garage addCar: car];

      car = makeCar (@"ElvIs", @"Acura", @"Legend", 1989, 4, 28123.4, 151);
      [garage addCar: car];
      
      car = makeCar (@"Phoenix", @"Pontiac", @"Firebird", 1969, 2, 85128.3, 345);  

      [garage addCar: car];
      
      car = makeCar (@"Streaker", @"Pontiac", @"Silver Streak", 1950, 2, 39100.0, 36);
      [garage addCar: car];
      car = makeCar (@"Judge", @"Pontiac", @"GTO", 1969, 2, 45132.2, 370);
      [garage addCar: car];
      car = makeCar (@"Paper Car", @"Plymouth", @"Valiant", 1965, 2, 76800, 105);
      [garage addCar: car];
      car = makeCar (@"Herbie", @"Honda", @"CRX", 1984, 2, 34000, 58);
      [garage addCar: car];
      [garage print];
    }

      

      以下谓词的使用都是在main函数中定义的。

      在没有谓词情况下,要判断创建的辆车名是否是叫Herbie的呢?我们可能会使用下面的代码:

        if ([car.name isEqualToString:@"Herbie"]) {
            NSLog(@"Match");
        }else{
            NSLog(@"NotMatch");
        }

      

      下面我们来看一下使用谓词的情况下应该怎么做?   

    //    基本的谓词用法,创建了一个谓词,这个谓的判断条件是汽车的name Herbie相同

    //    需要注意的是,如果不使用单引号的话,谓词格式将会把字符串理解成keyPath,如果使用 (keyPath是KVC的使用)

    //    单引号括起来的话,谓词会理解为字符串

           

     

      NSPredicate *predicate;
      //谓词的初始化
       predicate = [NSPredicate predicateWithFormat:@"name=='Herbie'"];
      //谓词的判断条件 (返回一个Boolen值来判断这个对象是否满足上面的谓词条件)
       BOOL match = [predicate evaluateWithObject:car];
    
        if (match) {
          NSLog(@"Match");
       }else
      
      {        NSLog(@"NotMatch");    }

      看到上面的代码有人会想,这样的方法不是没有上面的代码简单吗?我们来看谓词的其它使用情况

      

        predicate = [NSPredicate predicateWithFormat:@"engine.horsepower > 150"];
        match = [predicate evaluateWithObject:car];
        if (match) {
            NSLog(@"car's engine horsepower > 150");
        }else
        {
            NSLog(@"car's engine horsepower no > 150");
        }

       这样是不是看到谓词的好处了,如果在不使用谓词的情况下,就应该先找到发动机,然后再找发动机马力大于150的,是不是感到繁琐。能过使用谓词就可以一步到位找到。

     

      我们继续来看谓词的其它用法

      //    现在要实现一个功能:将车库里的汽车,凡是发动机马力大于150的全部列出来

       //    在没有谓词的情况下:1、取出车库里的汽车

                  2、创建一个可变数据用于存放满足条件的汽车

                    3、遍历车库里的每一辆汽车,判断是否满足条件

                  4、如果满足的话,将这辆汽车放到可变数组里。

      下面我们来对比一下使用谓词和不使用谓词来实现上述功能 

    //不使用谓词的情况 
     
    //该方法是从车库中取出所有的汽车,定义在Garage.m中

      NSArray *cars = [garage cars];

       
      NSMutableArray *favCars = [[NSMutableArray alloc] initWithCapacity:3]; for (Car *favCar in cars) { if (favCar.engine.horsepower > 150) { [favCars addObject:favCar]; } } NSLog(@"my fav car is %@",favCars);
     

    //同上的功能,在有谓词的情况下只需要1、创建一个谓词,条件是汽车马力大于150,2、使用谓词得到结果
    //定义一个谓词 满足engine.horsepower > 150

      predicate = [NSPredicatepredicateWithFormat:@"engine.horsepower > 150"];

      //通过谓词给出的条件过滤,

     NSArray *myFavCars = [cars filteredArrayUsingPredicate:predicate];

       NSLog(@"myFavCars is %@",myFavCars);

       谓词也可以在外界传递参数

        int horPower = 50;
        predicate = [NSPredicate predicateWithFormat:@"engine.horsepower > %d",horPower];
        myFavCars = [cars filteredArrayUsingPredicate:predicate];
        NSLog(@"%@",myFavCars);
        
        NSString *carName = @"Herbie";
        predicate = [NSPredicate predicateWithFormat:@"name == %@",carName];
        myFavCars = [cars filteredArrayUsingPredicate:predicate];
        NSLog(@"%@",myFavCars);

      

      在谓词里有一个格式说明符叫%K(大写),用于表示keyPath

        NSString *keyPath = @"name";
        NSString *condition = @"Herbie";
        predicate = [NSPredicate predicateWithFormat:@"%K == %@",keyPath,condition];
        myFavCars = [cars filteredArrayUsingPredicate:predicate];
        NSLog(@"xxxxxx%@",myFavCars);

      

     谓词里还有一个比较强大的功能就是占位符($)的使用。注意在使用占位符的时候后面$后面的属性要大写,在使用的时候也要用和定义的时候一样的大写。

      NSPredicate *predicateTemplate = [NSPredicate predicateWithFormat:@"name == $NAME"];
        
        NSDictionary *varDict = [NSDictionary dictionaryWithObjectsAndKeys:@"Herbie",@"NAME", nil];
        
        predicate = [predicateTemplate predicateWithSubstitutionVariables:varDict];
        
        myFavCars = [cars filteredArrayUsingPredicate:predicate];
        NSLog(@"-----%@",myFavCars);
        
        
        predicateTemplate = [NSPredicate predicateWithFormat:@"engine.horsepower > $POWER"];
        varDict = @{@"POWER":@150};
        predicate = [predicateTemplate predicateWithSubstitutionVariables:varDict];
        myFavCars = [cars filteredArrayUsingPredicate:predicate];
        NSLog(@"+++++++%@",myFavCars);

      谓词的使用还可以用一些比较运算符和逻辑运算符 如:> < >= <= != <> 比较运算符

      逻辑运算符与或非相对应的标识符 AND OR(逻辑运算符全部要大写)

        predicate = [NSPredicate predicateWithFormat:@"(engine.horsepower  < 59) AND (engine.horsepower > 200)"];
        myFavCars = [cars filteredArrayUsingPredicate:predicate];
        [garage print];
        NSLog(@"50-200 %@",myFavCars);
        
        
        predicate = [NSPredicate predicateWithFormat:@"name < 'Newton'"];
        myFavCars = [cars filteredArrayUsingPredicate:predicate];
        NSLog(@"%@",myFavCars);

      谓词也可以直接使用硬编码的格式也可以不直接使用,占位符也可以使用

      

    //    直接使用硬编码的方式来表示两个数据之间的值的覆盖件
    
        predicate = [NSPredicatepredicateWithFormat:@"engine.horsepower BETWEEN {50,200}"];
    
        myFavCars = [cars filteredArrayUsingPredicate:predicate];
    
        NSLog(@"%@",myFavCars);
    
       //使用变量来表示两个数据值之间的值的条件
    
      //定义表示范围的值 NSArray *betweens = @[@50,@200]; predicate = [NSPredicatepredicateWithFormat:@"engine.horsepower BETWEEN %@",betweens]; myFavCars = [cars filteredArrayUsingPredicate:predicate]; NSLog(@"%@",myFavCars);

     

         //占位符来表两个数据之间的值的条件。

         predicateTemplate = [NSPredicatepredicateWithFormat:@"engine.horsepower BETWEEN $POWERS"];

         varDict = @{@"POWERS" : @[@50,@200]};

          predicate = [predicateTemplate predicateWithSubstitutionVariables:varDict];

        

          myFavCars = [cars filteredArrayUsingPredicate:predicate];

          NSLog(@"%@",myFavCars);

      谓词的使用还可以使用集合的概念的情况:(IN)

      

    //    创建一个谓词对象, 使用这个对象,查找出车库里车名为Herbie Snugs Badger Flag的汽车的信息
    //  就是把名字为下面的全部取出来
    predicate = [NSPredicate predicateWithFormat:@"name IN {'Herbie','Snugs','Badger','Flag'}"]; myFavCars = [cars filteredArrayUsingPredicate:predicate]; NSLog(@"%@",myFavCars);
    // SELF 在这里表示的是使谓词进行最终计算的时候的对象,实际就是cars数组里的car对象。 predicate = [NSPredicate predicateWithFormat:@"SELF.name IN {'Herbie','Snugs','Badger','Flag'}"]; myFavCars = [cars filteredArrayUsingPredicate:predicate]; NSLog(@"%@",myFavCars); // 想把车库里的所有车的名字取出来,使用kvc就可以完成集合的整体操作 NSArray *carNames = [cars valueForKey:@"name"]; NSLog(@"carNames is %@",carNames); predicate = [NSPredicate predicateWithFormat:@"SELF IN {'Herbie','Snugs','Badger','Flag'}"]; myFavCars = [carNames filteredArrayUsingPredicate:predicate]; NSLog(@"%@",myFavCars); // 需要注意的是, 在谓词格式里面,需要遵守一个规则, 就是关键字大写 // 查找以下两个车库的相同名字的汽车 // {'Herbie','Snugs','Badger','Flag'} {'Judge','Paper Car' ,'Badger','Phoenix'}
    // 该方法的作用是比较在两个数组里面共有名字,然后取出来(相当于集合中的取交集)
    NSArray *names1 = @[@"Herbie",@"Snugs",@"Badger",@"Flag"]; NSArray *names2 = @[@"Judge",@"Paper Car" ,@"Badger",@"Phoenix"]; predicate = [NSPredicate predicateWithFormat:@"SELF IN %@",names1]; myFavCars = [names2 filteredArrayUsingPredicate:predicate]; NSLog(@"%@",myFavCars);

      在谓词的使用中也可以使用通配符。下面我们来看一下通配符在谓词中的使用。

    //    从当前的车库里,找到名字中包含有i字母的汽车
        
    //  这个方法中的作用是把名字中的包含i字母的名字取出来,关键字用的是CONTAINS[cd]其中[]中的c的意思是忽略字母的大小写,d是跟字母的重音有关。
    // predicate = [NSPredicate predicateWithFormat:@"SELF.name CONTAINS[cd] %@",@"i"];
    //  这个方法使用的是LIKE,下面的判断是名字中含有字母vi。
    // predicate = [NSPredicate predicateWithFormat:@"SELF.name LIKE[c] '*vi*'"];

    //下面这个也是通配符的使用,使用关键字MATCHES.判断心字母H开头,并且以字母i结束。 predicate = [NSPredicate predicateWithFormat:@"SELF.name MATCHES 'H[a-z]*i?'"]; myFavCars = [cars filteredArrayUsingPredicate:predicate]; NSLog(@"%@",myFavCars);

      当然了,也可以在谓词中使用运算符,像SUM来求和之类的,有兴趣的大家可以测试一下,关于谓词的使用就先介绍到这里。

        

      

  • 相关阅读:
    关于题目中的内存限制
    手动实现最小堆和最大堆(优先队列)
    线性筛素数(欧拉筛)+前缀和优化
    并查集
    快速排序

    字典按中文姓名排序
    oc程序代码
    学生字典计算年龄差 随机50个数
    nsset
  • 原文地址:https://www.cnblogs.com/xinianhao/p/3729770.html
Copyright © 2011-2022 走看看