Predicate常被翻译成“谓词”,它被用于描述一个对象的性质或者对象间的相互关系,比如“小明是程序员”这个句子中的“是程序员”就是一个谓词。
在Cocoa中,NSPredicate是可以根据对象的性质或者相互关系来进行逻辑判断的工具。
只看概念不太好理解,直接上代码:
NSPredicate *isRich = [NSPredicate predicateWithFormat:@"account.balance > 5000000"];
Person *zhangSan = [[Person alloc] initWithName:@"ZhangSan" andBalance:9999];
Person *bill = [[Person alloc] initWithName:@"Bill" andBalance:1000000000];
NSLog(@"%d", [isRich evaluateWithObject:zhangSan]); // 输出0
NSLog(@"%d", [isRich evaluateWithObject:bill]); // 输出1
创建NSPredicate对象
从上面的例子里可以看到,我们可以通过NSPredicate提供的类方法,用格式化字符串方便地创建NSPredicate对象。
Cocoa为格式化字符串提供了丰富的语法支持:
比较运算符:<、<=、>、>=、=、!=、BETWEEN
[NSPredicate predicateWithFormat:@"account.balance > 5000000"];
[NSPredicate predicateWithFormat:@"account.balance BETWEEN {100, 1000}"];
复合运算符:OR、AND和NOT
[NSPredicate predicateWithFormat:@"startDate <= %@ AND endDate >= %@", now, now];
字符串判断:BEGINSWITH、CONTAINS
、ENDSWITH、LIKE、MATCHES
[NSPredicate predicateWithFormat:@"name BEGINSWITH 'Zhang'" ];
[NSPredicate predicateWithFormat:@"name CONTAINS 'ang'" ];
// LIKE支持通配符,*代表任意个字符,?代表仅有一个字符
[NSPredicate predicateWithFormat:@"url LIKE 'https://*.taobao.com*'" ];
// MATCHES支持正则表达式
NSString *regex = @"[0-9]*";
[NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
集合运算:ANY、SOME、ALL、NONE、IN
NSArray *names = @[@"ZhangSan", @"LiSi", @"WangWu"];
NSPredicate *anyIsZhang = [NSPredicate predicateWithFormat:@"ANY SELF BEGINSWITH 'Zhang'" ];
NSLog(@"%d", [anyIsZhang evaluateWithObject:names]);
常量和占位符:%@、%k、SELF
// 在格式化字符串的语法中,常量必须用引号包围起来,而属性名字不用
// 比如在name BEGINSWITH 'Zhang'这个格式化字符串里,name为属性,Zhang为常量
// 上面的例子大都是把常量硬编码在字符串里,但是我们的实际开发中会更多的用到占位符
[NSPredicate predicateWithFormat:@"name BEGINSWITH %@", familyName];
// 需要注意的是,在%@作为占位符时,它会被自动加上引号
// "name BEGINSWITH %@" 会变成 "name BEGINSWITH 'familyName'"
// 所以%@只能作为常量的占位符。
// 当我们想动态的填入属性名的时候,我们就必须这样写:
[NSPredicate predicateWithFormat:@"%k BEGINSWITH %@", propertyName, familyName];
// 在苹果的官方文档里面有一个%@错误用法的示范,大家可以想一下这样用为什么不对:
predicate = [NSPredicate predicateWithFormat:@"SELF like %@*%@", prefix, suffix];
ok = [predicate evaluateWithObject:@"prefixxxxxxsuffix"];
除了上面提到的使用格式化字符串创建NSPredicate的方法之外,Cocoa提供了另外两种创建NSPredicate的方法。它们的语法相对复杂,在这里就不多赘述了。
NSPredicate对象的用法
NSPredicate的最基本用法,就是创建一个NSPredicate对象,把要判断的对象传递给它,使用evaluateWithObject:方法判断:
NSPredicate *isRich = [NSPredicate predicateWithFormat:@"account.balance > 5000000"];
Person *zhangSan = [[Person alloc] initWithName:@"ZhangSan" andBalance:9999];
NSLog(@"%d", [isRich evaluateWithObject:zhangSan]); // 输出0
我们还可以用NSPredicate来作为集合的过滤器用,这种写法相当简洁优雅:
NSArray *names = @[@"ZhangSan", @"LiSi", @"WangWu"];
NSPredicate *containsN = [NSPredicate predicateWithFormat:@"SELF CONTAINS 'n'" ];
NSLog(@"%@", [names filteredArrayUsingPredicate:containsN]); // 输出["ZhangSan", "WangWu"]