Objective-C中的NSPredicate
编写软件时,经常需要获取一个对象集合,并通过某些已经条件计算该集合的值。你需要保留符合某个条件的对象,删除那些不满足条件的对象,从而提供一些有意义的对象。
在使用软件iPhoto的过程中,经常会看到这种现象,如果通知iPhoto仅显示等级为三星级或三星级以上的图片,则指定的条件为“照片的等级必须为三星级或三星级以上”。这样,所有照片都需要经过该过滤器过滤。满足条件的对象通过了过滤器,而其他对象被筛除了。最后,iPhoto将显示出所有高质量的图片。
Cocoa提供了一个名为NSPredicate的类,它用于指定过滤器的条件。可以创建NSPredicate对象,通过该对象准确地描述所需的条件,对每个对象通过谓词进行筛选,判断它们是否与条件相匹配。这里的“谓词”通常用在数学和计算机科学概念中,表示计算真值或假值的函数。
Cocoa用NSPredicate描述查询的方式,原理类似于在数据库中进行查询。可以在数据库风格的API中使用NSPredicate类,例如Core Data和Spotlight。可以将NSPredicate看成另一种间接操作方式。例如,如果需要查询满足条件的机器人,可以使用谓词对象进行检查,而不必使用代码进行显示查询。通过交换谓词对象,可以使用通用代码对数据进行过滤,而不必对相关条件进行硬编码。
创建
1)方式一
创建许多对象,并将它们组合起来。如果正在构建通用用户接口来指定查询,采用这种方式比较简单。
2)方式二
查询代码中的字符串。
1 | Car *car; |
计算谓词
1 | BOOL match = [predicate evaluateWithObject:car]; |
另外一个谓词:
1 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"engine.horsepower >150"]; |
过滤器
如果我们不必像上文那样编写for循环和if语句,这有什么不好?实际上,某些类别将谓词过滤方法添加到了Cocoa集合类中。-filteredArrayUsingPredicate:
是NSArray数组中的一种类别方法,它将循环过滤数组内容,根据谓词计算每个对象的值,并将值为YES的对象累积到将被返回的新数组中:
1 | NSArray *results; |
假如有一个可变数组,你需要剔除不属于该数组的所有项目:
1 | NSMutableArray *carsCopy = [cars mutableCopy]; |
格式说明符
资深编程人员都知道,硬编码并非好方法,因此,我们可以通过格式符构建谓词:
1 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"engine.horsepower > %d", 50]; |
运算符
NSPredicate的格式字符串包含大量不同的运算符。
1)比较和逻辑运算符
谓词字符串语法支持C语言中一些常用的运算符,例如等号运算符==和=。
不等号运算符具有各种形式:
1 | >:大于 |
此外,谓词字符串语法还支持括号表达式和AND、OR、NOT逻辑运算符或者C样式的等效表达式&&、||和!。
2)数组运算符
谓词字符串“(engine.horsepower> 50) OR (engine.horsepower < 200)”是一种十分常见的模式。等效于:
1 | predicate= [NSPredicate predicateWithFormat:@"engine.horespower BETWEEN {50,200}"]; |
花括号表示数组,BETWEEN将数组中第一个元素看成是数组的下界,第二个元素看成是数组的上界。
1 | NSArray *betweens = [NSArray arrayWithObjects:[NSNumber numberWithInt:50],[NSNumber numberWithInt:200], nil]; |
数组不仅仅用来指定某个区间的端点值。你可以使用IN运算符查找数组中是否含有某个特定值。
1 | predicate = [NSPredicate predicateWithFormat:@"name IN {'Herbie', 'Snugs', 'Badger','Flap'}"]; |