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