您的位置:首页 > 移动开发 > IOS开发

iOS中的谓词NSPredicate的使用

2014-05-15 12:37 344 查看
  今天写一篇关于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来求和之类的,有兴趣的大家可以测试一下,关于谓词的使用就先介绍到这里。

    

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: