iOS 谓词(NSPredicate)
文档定义
NSPredicate:A definition of logical conditions used to constrain a search either for a fetch or for in-memory filtering.(逻辑条件的定义,用于限制对访存或内存中过滤的搜索。)
谓词代表逻辑条件,可用于过滤对象集合。 虽然直接从NSComparisonPredicate,NSCompoundPredicate和NSExpression的实例创建谓词是很常见的,但是您通常会根据由NSPredicate上的类方法解析的格式字符串来创建谓词。 谓词格式字符串的示例包括:
1. 简单比较,例如成绩==“ 7”或“ Shaffiq”这样的名字
2. 大小写不敏感的查找,例如名称contains [cd]“ itroen”
3. 逻辑运算,例如(名字,例如“ Mark”)或(姓氏,例如“ Adderley”)
4. 时间范围限制,例如{ TOMORROW}之间的日期。
5. 关系条件,例如group.name之类的“ work *”
6. 聚合操作,例如@ sum.items.price <1000
有关完整的语法参考,请参阅《谓词编程指南》。
谓词的创建
谓词字符串解析器对空格不敏感,对关键字不区分大小写,并且支持嵌套的括号表达式。 它还支持printf样式的格式说明符(例如%x和%@)-请参阅格式化字符串对象。 变量用 VARIABLE_NAME)-有关更多详细信息,请参见使用谓词模板创建谓词。
predicateFormat 后面的字符串如何设置可以查看 谓词格式字符串语法
解析器不执行任何语义类型检查。 它会尽力而为地创建合适的表达式,但是(尤其是在替换变量的情况下)可能会生成运行时错误。(确保format字符串是正确的,否则会运行时崩溃)
//初始化方法
public convenience init(format predicateFormat: String, _ args: CVarArg...)
例子:
//like[c]是不区分大小写
let pre = NSPredicate.init(format: "(lastName like[c] %@) AND (birthday > %@)", "abc",NSNumber.init(value: 10))
let result = pre.evaluate(with: ["lastName":"abc","birthday":11])
print(result)// true
出来通过固定字符串创建谓词以外,还支持 字符串常量,变量和通配符创建谓词
例子:
let pre = NSPredicate.init(format: "lastName like[c] 'S*'")
let result = pre.evaluate(with: ["lastName":"sss"])
print(result)// true
var prefix = "prefix"
var suffix = "suffix"
let pre = NSPredicate.init(format: "lastName like[c] %@", "\(prefix + "*" + suffix)")
let result = pre.evaluate(with: ["lastName":"prefixxxxxxsuffix"])
print(result)// true
/// 数字,bool 类型需要用NSNumberv包裹
let pre = NSPredicate.init(format: "age > %@",NSNumber.init(value: 20))
let result = pre.evaluate(with: ["age":30])
print(result)// true
如果要指定动态属性名称,请在格式字符串中使用%K,如以下片段所示。
由于使用%@将字符串变量替换为格式字符串时,字符串变量用引号引起来,因此您不能使用%@指定动态属性名称,如以下示例所示
var key = "name"
var value = "abc"
let pre = NSPredicate.init(format: "%@ like %@",key,value)
let result = pre.evaluate(with: ["name":"abc"])
print(result)// false
上面这种情况下,谓词格式字符串的值为“name”(注意是带双引号的)
也就是format字符串是 “ “name” like xx 所以匹配结果是false
将key 部分的%@ 换成%K 就能正确匹配
var key = "name"
var value = "abc"
let pre = NSPredicate.init(format: "%K like %@",key,value)
let result = pre.evaluate(with: ["name":"abc"])
print(result)// true
NSComparisonPredicate和NSCompoundPredicate提供方便的方法,使您可以轻松地分别创建复合谓词和比较谓词。 NSComparisonPredicate提供了许多运算符,从简单的相等性测试到自定义函数。详系可以看Creating Predicates Directly in Code
谓词的使用
判断是否符合谓词 可以使用NSPredicate方法evaluateWithObject:并传入要对其评估谓词的对象。也可以将谓词与任何对象类一起使用,但是该类必须支持要在谓词中使用的键的键值编码(key-value coding)。
- 在数组中使用谓词
//filtered 是NSArray中的方法,swift中的Array没有这个方法,Array 可以使用filter(isIncluded: (String) throws -> Bool )
let array = NSArray.init(array: ["Nick", "Ben", "Adam", "Melissa"])
let pre = NSPredicate.init(format: "SELF beginswith[c] 'b'")
let result = array.filtered(using: pre)
print(result)//[Ben]
- Key-Paths 使用 谓词
//KVC的类必须继承自NSObject,变量并且用@objc修饰,否则直接报错
class Person:NSObject{
@objc var age = 10
}
var person = Person()
let pre = NSPredicate.init(format: "age < %@",NSNumber(value: 20))
let result = pre.evaluate(with: person)
print(result)//true
- 筛选nil值
let arr = NSArray.init(array: [["name":"小明"],["name":"小红","age":20]])
let pre = NSPredicate.init(format: "age != nil")
let result = arr.filtered(using: pre)
print(result)
/*
[{
age = 20;
name = "\U5c0f\U7ea2";
}]
*/
- CoreData 使用谓词
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Employee"
inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSNumber *salaryLimit = <#A number representing the limit#>;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"salary > %@", salaryLimit];
[request setPredicate:predicate];
NSError *error;
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
- 使用正则表达式
let predicate = NSPredicate(format: "SELF MATCHES %@" ,"\\d*")
let result = predicate.evaluate(with: "123456789")
print(result)//true
let predicate = NSPredicate(format: "(name matches %@)&&(age matches %@)" ,"[a-z]*","\\d*")
let result = predicate.evaluate(with: ["name":"abcd","age":"20"])
print(result)//true
谓词format
-
比较符号,都是针对于左边表达式和右边表达式
- > 大于
- > =大于等于
- < 小于
- <=小于等于
- ==等于
- != 或者<> 不等于
- BETWEEN 介于两者之间,包括上下限
-
复合比较
- && 或者AND 逻辑与
- || 或者 OR 逻辑或
- !或者NOT 逻辑非
-
字符串比较
- BEGINSWITH 左边表达式以右边表达式开头
- CONTAINS 左边表达式包含右边表达式
- ENDSWITH 左边表达式以右边表达式结尾
- LIKE 左边表达式和右边表达式相似(简单的正则表达式匹配,?匹配一个字符,*匹配0个或者多个字符)
- MATCHES 可以实现较为复杂的曾则表达式匹配
- 用方括号加cd来不区分大小写和变音符号
- IN 左边的表达式在右边的集合里
- UTI-CONFORMS-TO该运算符的左侧参数是一个表达式,其计算结果为您要匹配的通用类型标识符(UTI)。 右侧参数是一个表达式,其计算结果为UTI。 如果左侧表达式返回的UTI符合右侧表达式返回的UTI,则比较的结果为TRUE。有关哪些类型符合给定类型的信息,请参见《统一类型标识符参考》中的系统声明的统一类型标识符
- UTI-EQUALS 该运算符的左侧参数是一个表达式,其计算结果为您要匹配的通用类型标识符(UTI)。 右侧参数是一个表达式,其计算结果为UTI。 如果左侧表达式返回的UTI等于右侧表达式返回的UTI,则比较结果为TRUE。
-
集合操作
- ANY,SOME
指定以下表达式中的任何元素。例如,任何child.age <18。 - ALL
指定以下表达式中的所有元素。例如,所有children.age <18。 - NONE
不指定以下表达式中的任何元素。例如,NONE children.age <18。这在逻辑上等效于NOT(ANY ...)。 - IN
等效于SQL IN操作,左侧必须出现在右侧指定的集合中。
例如,命名为IN {'Ben','Melissa','Nick'}。集合可以是数组,集合或字典,如果是字典,则使用其值。 - array[index]
指定数组数组中指定索引处的元素。 - array[FIRST]
指定数组数组中的第一个元素。 - array[LAST]
指定数组数组中的最后一个元素。 - array[SIZE]
指定数组数组的大小。
- ANY,SOME
-
文字操作
单引号和双引号产生相同的结果,但它们不会彼此终止。 例如,“ abc”和“ abc”相同,而“a'b'c”等效于a,“ b”,c的以空格分隔的串联。- FALSE,NO
逻辑错误。 - TRUE ,YES
逻辑上正确。 - NULL,NIL
空值。 - SELF
表示被评估的对象。 - “text”
字符串。 - 'text'
字符串。 - 逗号分隔的文字数组
例如,{'逗号','分隔','文字','数组'}。 - 标准整数和定点表示法
例如1、27、2.71828、19.75。 - 浮点数与指数
例如9.2e-5。 - 0x
用于表示十六进制数字序列的前缀。 - 0o
用于表示八进制数字序列的前缀。 - 0b
用于表示二进制数字序列的前缀。
- FALSE,NO