NSPredicate 谓词使用记录


NSPredicate类是用来定义逻辑条件约束的获取或内存中的过滤搜索。

开发中经常需要从集合中查找到某个或某些值,或者通过过滤得到想要的内容,这都是家常便饭的事儿。所以,我们常见的就是需要遍历集合,加条件判断,然后得到符合条件的结果。然而,遍历是件很耗内存的事儿,特别是在移动端开发,多重的for循环遍历,是要尽量避免的。此文主要是来介绍NSPredicate类,这种类似于SQL语句通过过滤集合内容的方式,来避免进行集合遍历的方法。

基本语法

比较运算符
  • = , == : 判断两个表达式是否相等
  • = , => : 判断左边表达式的值是否大于或等于右边表达式的值

  • <= , =< : 判断左边表达式的值是否小于或等于右边表达式的值
  • : 判断左边表达式的值是否大于右边表达式的值

  • < : 判断左边表达式的值是否小于右边表达式的值
  • != , <> : 判断左边表达式的值是否不相等右边表达式的值
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age >= 55"];
    

集合运算符
  • BETWEEN :必须满足表达式 BETWEEN {下限, 上限}的格式,要求该表达式必须大于或等于下限,并小于或等于上限
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age BETWEEN {11, 55}"];
    
    age代表了集合中对象的一个实例属性,此时集合中的对象是一个个的实体。

  • IN :必须满足表达式 IN {元素0, 元素1, 元素2...}的格式,要求该表达式必须包含有{}中的任一元素。
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name IN {'Seven', 'Eight'}"];
    

  • ANY , SOME : 集合中任意一个元素满足条件,就返回YES
  • ALL : 集合所有元素满足条件,才返回YES
  • NONE : 集合中没有任何元素元素满足条件,就返回YES
逻辑运算符
  • && , AND : 逻辑与,要求左右表达式的值都为YES,结果才为YES
  • || , OR : 逻辑或,要求只要左右表达式中有一个的值都为YES,结果就为YES
  • ! , NOT : 逻辑非,对原有表达式取反
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = 'One' && age = 11"];
    

字符串间运算符
  • BEGINSWITH : 检查某个字符串是否以指定的字符串
  • ENDSWITH : 检查某个字符串是否以指定的字符结尾
  • CONTAINS : 检查某个字符串是否包含指定的字符串
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] 'F'"];
    

注: 字符串比较都是区分大小写和重音符号的。如:café和cafe是不一样的,Cafe和cafe也是不一样的。如果希望字符串比较运算不区分大小写和重音符号,请在这些运算符后使用[c],[d]选项。其中[c]是不区分大小写,[d]是不区分重音符号,其写在字符串比较运算符之后,比如:name LIKE[cd] 'cafe',那么不论name是cafe、Cafe还是café上面的表达式都会返回YES。

  • LIKE : 检查某个字符串是否匹配指定的字符串模板
  • 通配符?代表一个任意字符
  • 通配符*代表任意多个字符
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name LIKE[cd] 'T*'"];
    
  • MATCHES : 检查某个字符串是否匹配指定的正则表达式。虽然正则表达式的执行效率是最低的,但其功能是最强大的,也是我们最常用的。
%K、%@、$VALUE的用法
  • %K : 字段占位符 (K必须是大写)
  • %@ : 值占位符
  • $VALUE : VALUE只是一个普通字符串,当做标识使用,可以任意替换,但要统一
    NSString *nameStr = @"name";
    NSString *valueStr = @"Seven";
    NSPredicate *predicate0 = [NSPredicate predicateWithFormat:@"%K CONTAINS %@", nameStr, valueStr];
    NSPredicate *pred1 = [NSPredicate predicateWithFormat:@"%K > $VALUE", @"age"];
    NSPredicate *predicate1 = [pred1 predicateWithSubstitutionVariables:@{@"VALUE" : @1}];
    
实例运用
// 取出self.array2中  self.array2 & self.array1都不包含的元素
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", self.array1];
NSLog(@"%@", [self.array2 filteredArrayUsingPredicate:predicate]);

// 取出self.array1 & self.array2 都包含的元素
predicate = [NSPredicate predicateWithFormat:@"SELF IN %@", self.array1];
NSLog(@"%@", [self.array2 filteredArrayUsingPredicate:predicate]);

// 取出self.array1中  self.array2 & self.array1都不包含的元素
predicate = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", self.array2];
NSLog(@"%@", [self.array1 filteredArrayUsingPredicate:predicate]);
谓词过滤集合

其实谓词本身就代表了一个逻辑条件,计算谓词之后返回的结果永远为BOOL类型的值。而谓词最常用的功能就是对集合进行过滤。当程序使用谓词对集合元素进行过滤时,程序会自动遍历其元素,并根据集合元素来计算谓词的值,当这个集合中的元素计算谓词并返回YES时,这个元素才会被保留下来。请注意程序会自动遍历其元素,它会将自动遍历过之后返回为YES的值重新组合成一个集合返回。

  • NSArray提供了如下方法使用谓词来过滤集合,

    使用指定的谓词过滤NSArray集合,返回符合条件的元素组成的新集合:

- (NSArray<ObjectType>*)filteredArrayUsingPredicate:(NSPredicate *)predicate:

  • NSMutableArray提供了如下方法使用谓词来过滤集合,

    使用指定的谓词过滤NSMutableArray,剔除集合中不符合条件的元素:

- (void)filterUsingPredicate:(NSPredicate *)predicate

  • NSSet提供了如下方法使用谓词来过滤集合,

    作用同NSArray中的方法:

- (NSSet<ObjectType> *)filteredSetUsingPredicate:(NSPredicate *)predicate NS_AVAILABLE(10_5, 3_0)

  • NSMutableSet提供了如下方法使用谓词来过滤集合:

    作用同NSMutableArray中的方法。通过上面的描述可以看出,使用谓词过滤不可变集合和可变集合的区别是:过滤不可变集合时,会返回符合条件的集合元素组成的新集合;过滤可变集合时,没有返回值,会直接剔除不符合条件的集合元素

- (void)filterUsingPredicate:(NSPredicate *)predicate NS_AVAILABLE(10_5, 3_0)

  • NSPredicate过滤数组中对象的keyPath

    有时候我们匹配数组所有元素,会用到的元素的变量[的属性],也就是keyPath,那么我们可以这么写 比如有一个数组items,他的元素类型为MapModel,而MapModel有一个变量为model,model有一个属性为mapId,那么我们就比较数组中mapId == curMapModel.mapId 的所有元素

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"model.'mapId' == %@", curMapModel.mapId];
NSArray *filtersOfGps = [items filteredArrayUsingPredicate:predicate];

附件: