【IOS 开发学习总结-OC-32】★OC之foundation 框架——谓词(NSPredicate)

来源:互联网 发布:郑州直销软件靠谱吗 编辑:程序博客网 时间:2024/05/16 18:41

NSPredicate用于定义一个逻辑条件,通过该条件可执行搜索或内存中的过滤操作。

定义谓词

谓词由NSPredicate对象来代表,它有3个子类:NSComparisonPredicate,NSCompoundPredicate,NSExpression。
虽然程序实际创建的通常是NSPredicate的子类的实例,但实际编程中会直接使用NSPredicate的predicateWithFormat: 方法,以一个谓词字符串为参数来创建NSPredicate对象。

创建谓词后,如果谓词中没有占位符参数,即可使用NSPredicate的evaluateWithObject:方法计算谓词的结果。该结果总是一个 BOOL 值;如果该谓词中有占位符参数,则需经过如下两步来计算谓词的结果。
1. 调用谓词的 predicateWithSubstitutionVariables:方法为占位符参数设置参数值。
2. 执行谓词的evaluateWithObject:方法计算谓词的返回结果。

NSPredicate提供的这个evaluateWithObject:<#(nullable id)#> substitutionVariables:方法,可以同时完成以上2步。

示例代码:
FKUser.h

#import <Foundation/Foundation.h>@interface FKUser : NSObject@property (nonatomic , copy) NSString* name;@property (nonatomic , copy) NSString* pass;- (id) initWithName:(NSString*) aName    pass:(NSString*) aPass;- (void) say:(NSString*) content;@end

FKUser.m

//  Created by yeeku on 2013-4-21.//  Copyright (c) 2013年 crazyit.org. All rights reserved.#import "FKUser.h"@implementation FKUser@synthesize name;@synthesize pass;- (id) initWithName:(NSString*) aName    pass:(NSString*) aPass{    if(self = [super init])    {        name = aName;        pass = aPass;    }    return self;}- (void) say:(NSString*) content{    NSLog(@"%@说:%@",self.name , content);}// 会重写isEqual:方法,重写该方法的比较标准是,// 如果两个FKUser的name、pass相等,即可认为两个FKUser相等。- (BOOL) isEqual:(id)other{    if(self == other)    {        return YES;    }    if([other class] == FKUser.class)    {        FKUser* target = (FKUser*)other;        return [self.name isEqualToString:target.name]            && [self.pass isEqualToString:target.pass];    }    return NO;}// 会重写isEqual:方法,重写该方法的比较标准是,// 如果两个FKUser的name、pass相等,即可认为两个FKUser相等。- (NSUInteger) hash{    NSUInteger nameHash = name == nil ? 0 : [name hash];    NSUInteger passHash = pass == nil ? 0 : [pass hash];    return nameHash * 31 + passHash;}// 重写description方法,可以直接看到FKUser对象的状态- (NSString*) description{    return [NSString stringWithFormat:        @"<FKUser[name=%@, pass=%@]>"        , self.name , self.pass];}- (id)copyWithZone:(NSZone *)zone{    NSLog(@"--正在复制--");    // 复制一个对象    FKUser* newUser = [[[self class] allocWithZone:zone] init];    // 将被复制对象的实变量的值赋给新对象的实例变量    newUser->name = name;    newUser->pass = pass;    return newUser;}@end

NSPredicateTest.m

#import <Foundation/Foundation.h>#import "FKUser.h"int main(int argc , char * argv[]){    @autoreleasepool{        // 创建谓词,要求name的以s开头        NSPredicate* pred = [NSPredicate predicateWithFormat:            @"name like 's*'"];        FKUser* user1 = [[FKUser alloc] initWithName:@"sun"            pass:@"123"];        // 对user1对象使用谓词执行判断。        BOOL result1 = [pred evaluateWithObject:user1];        NSLog(@"user1的name是否以s开头:%d", result1);        FKUser* user2 = [[FKUser alloc] initWithName:@"bai"            pass:@"563"];        // 对user1对象使用谓词执行判断。                        BOOL result2 = [pred evaluateWithObject:user2];        NSLog(@"user2的name是否以s开头:%d", result2);    }}

运行结果:

2015-10-05 09:56:35.862 1005[1009:12112] user1name是否以s开头:12015-10-05 09:56:35.864 1005[1009:12112] user2name是否以s开头:0

使用谓词过滤集合

谓词的一个常用功能就是对集合进行过滤,当程使用谓词对集合元素进行过滤时,程序将会自动 遍历集合元素,并根据集合元素来计算谓词的值。只有当某个集合元素计算谓词并返回 YES 时,该元素才会被保存 下来 。

NSArray与NSMutableArray 用谓词过滤所使用的方法

NSArray提供的谓词过滤方法:

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

NSMutableArray提供的谓词过滤方法:

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

NSSet 与NSMutableSet 用谓词过滤所使用的方法

NSSet提供的谓词过滤方法:

filteredSetUsingPredicate:——使用指定谓词过滤 NSSet 集合,返回该集合中符合谓词条件的元素组成新集合。

NSMutableSet提供的谓词过滤方法:

filterUsingPredicate: ——使用指定谓词过滤 NSMutableSet 集合,剔除该集合中不符合谓词条件的元素。

使用谓词过滤可变集合与不可变集合的区别:

用谓词过滤不可变集合时,方法会返回符合条件元素的新集合;使用谓词过滤可变集合时,方法没有返回值,该方法直接剔除该集合中 不符合谓词条件的元素。

示例程序:

#import <Foundation/Foundation.h>#import "FKUser.h"int main(int argc , char * argv[]){    @autoreleasepool{        NSMutableArray* array = [NSMutableArray            arrayWithObjects: [NSNumber numberWithInt:50],            [NSNumber numberWithInt:50],            [NSNumber numberWithInt:42],            [NSNumber numberWithInt:20],            [NSNumber numberWithInt:64],            [NSNumber numberWithInt:56],nil];        // 创建谓词,要求该对象自身的值大于50        NSPredicate* pred1 = [NSPredicate predicateWithFormat:            @"SELF > 50"];        // 使用谓词执行过滤,过滤后只剩下值大于50的集合元素        [array filterUsingPredicate:pred1];        NSLog(@"值大于50的元素:%@" , array);        NSSet* set = [NSSet setWithObjects:            [[FKUser alloc] initWithName:@"孙悟空"                 pass:@"343"],            [[FKUser alloc] initWithName:@"金角大王"                 pass:@"231"],            [[FKUser alloc] initWithName:@"猪八戒"                 pass:@"659"],            [[FKUser alloc] initWithName:@"太上老君"                 pass:@"743"],            [[FKUser alloc] initWithName:@"银角大王"                 pass:@"985"], nil];        // 创建谓词,要求该对象的name值中包含'大王'        NSPredicate* pred2 = [NSPredicate predicateWithFormat:            @"name CONTAINS '大王'"];         // 执行过滤,过滤后集合只剩下两个元素                        NSSet* newSet = [set filteredSetUsingPredicate:pred2];        NSLog(@"%@" , newSet);                                                                  }}

运行结果:

2015-10-05 10:25:55.104 1005[1112:23750] 值大于50的元素:(    64,    56)2015-10-05 10:25:55.107 1005[1112:23750] {(    <FKUser[name=金角大王, pass=231]>,    <FKUser[name=银角大王, pass=985]>)}

在谓词中使用占位符参数

如果需要在谓词表达式中使用变量,块可以 考虑在谓词表达式中使用占位符参数,谓词表达式支持2个占位符参数。——%K和%@。

%K:用于动态传入属性名。
%@:用于动态设置属性值。

如果使用占位符,那么在调用predicateWithFormat: 时为各占位符传入参数值。
除此之外,

还可以在谓词表达式中使用动态改变的属性值。类似于环境变量 :
[NSPredicate predicateWithFormat:@"name CONTAINS $SUBSTR"];
$SUBSTR是一个可以动态变化的值,该谓词表达式的比较条件随着程序对$SUBSTR的改变而动态改变。

如果在谓词表达式中使用了$SUBSTR这样的占位符参数,为这些占位符传入参数的方法有如下2个方法:

  1. 先调用NSPredicate的predicateWithSubstitutionVariables方法为占位符参数设置参数值,该方法返回一个可用的NSPredicate对象。
  2. 直接调用NSPredicate的`evaluateWithObject:<#(nullable id)#> substitutionVariables:方法,同时完成参数 设置和计算结果。

示例代码:
PredicateArg.m

#import <Foundation/Foundation.h>#import "FKUser.h"int main(int argc , char * argv[]){    @autoreleasepool{        NSSet* set = [NSSet setWithObjects:            [[FKUser alloc] initWithName:@"孙悟空"                 pass:@"343"],            [[FKUser alloc] initWithName:@"金角大王"                 pass:@"231"],            [[FKUser alloc] initWithName:@"猪八戒"                 pass:@"659"],            [[FKUser alloc] initWithName:@"太上老君"                 pass:@"743"],            [[FKUser alloc] initWithName:@"银角大王"                 pass:@"598"], nil];        NSString* propPath = @"name";        NSString* value = @"大王";        // 创建谓词,该谓词中包含了2个占位符        // 后面的2个变量用于为占位符设置参数值        NSPredicate* pred = [NSPredicate predicateWithFormat:            @"%K CONTAINS %@" , propPath , value];        // 执行过滤,过滤后集合只剩下两个元素        NSSet* newSet = [set filteredSetUsingPredicate:pred];        NSLog(@"%@" , newSet);        // 创建谓词,该谓词表达式中使用%K占位符,该占位符使用pass代替        // 要求被比较对象的pass包含$SUBSTR子串。        NSPredicate* predTemplate = [NSPredicate predicateWithFormat:            @"%K CONTAINS $SUBSTR" , @"pass"];        // 使用NDDictionary指定SUBSTR的值为'43'        NSPredicate* pred1 = [predTemplate             predicateWithSubstitutionVariables:            [NSDictionary dictionaryWithObjectsAndKeys:                @"43" , @"SUBSTR", nil]];        // 执行过滤,过滤后集合只剩下两个元素        NSSet* newSet1 = [set filteredSetUsingPredicate:pred1];        NSLog(@"%@" , newSet1);        // 使用NDDictionary指定SUBSTR的值为'59'        NSPredicate* pred2 = [predTemplate             predicateWithSubstitutionVariables:            [NSDictionary dictionaryWithObjectsAndKeys:                @"59" , @"SUBSTR", nil]];        // 执行过滤,过滤后集合只剩下两个元素        NSSet* newSet2 = [set filteredSetUsingPredicate:pred2];        NSLog(@"%@" , newSet2);    }}

FKUser.h

#import <Foundation/Foundation.h>@interface FKUser : NSObject@property (nonatomic , copy) NSString* name;@property (nonatomic , copy) NSString* pass;- (id) initWithName:(NSString*) aName    pass:(NSString*) aPass;- (void) say:(NSString*) content;@end

FKUser.m

#import "FKUser.h"@implementation FKUser@synthesize name;@synthesize pass;- (id) initWithName:(NSString*) aName    pass:(NSString*) aPass{    if(self = [super init])    {        name = aName;        pass = aPass;    }    return self;}- (void) say:(NSString*) content{    NSLog(@"%@说:%@",self.name , content);}// 会重写isEqual:方法,重写该方法的比较标准是,// 如果两个FKUser的name、pass相等,即可认为两个FKUser相等。- (BOOL) isEqual:(id)other{    if(self == other)    {        return YES;    }    if([other class] == FKUser.class)    {        FKUser* target = (FKUser*)other;        return [self.name isEqualToString:target.name]            && [self.pass isEqualToString:target.pass];    }    return NO;}// 会重写isEqual:方法,重写该方法的比较标准是,// 如果两个FKUser的name、pass相等,即可认为两个FKUser相等。- (NSUInteger) hash{    NSUInteger nameHash = name == nil ? 0 : [name hash];    NSUInteger passHash = pass == nil ? 0 : [pass hash];    return nameHash * 31 + passHash;}// 重写description方法,可以直接看到FKUser对象的状态- (NSString*) description{    return [NSString stringWithFormat:        @"<FKUser[name=%@, pass=%@]>"        , self.name , self.pass];}- (id)copyWithZone:(NSZone *)zone{    NSLog(@"--正在复制--");    // 复制一个对象    FKUser* newUser = [[[self class] allocWithZone:zone] init];    // 将被复制对象的实变量的值赋给新对象的实例变量    newUser->name = name;    newUser->pass = pass;    return newUser;}@end

运行结果:

2015-10-06 08:07:49.423 1005[1295:38140] {(    <FKUser[name=金角大王, pass=231]>,    <FKUser[name=银角大王, pass=598]>)}2015-10-06 08:07:49.425 1005[1295:38140] {(    <FKUser[name=孙悟空, pass=343]>,    <FKUser[name=太上老君, pass=743]>)}2015-10-06 08:07:49.425 1005[1295:38140] {(    <FKUser[name=猪八戒, pass=659]>,    <FKUser[name=银角大王, pass=598]>)}

谓词表达式语法

只有使用谓词就要用到谓词表达式,该表达式是一个返回 BOOL 值的表达式。
谓词表达式由表达式,运算符和值组成。

基本的比较运算符

==, >=或==>,<= 或=<,>,< 以及
!=,<>:判断2个表达式是否不相等
BETWEEN:要求表达式的值必须大于或等于下限,比小于或等于 上限。(表达式BETWEEN{下限,,上限})

基本的逻辑运算符

AND,&&:逻辑与,要求2个表达式的值都为YES时,结果才是 YES。
OR,||:逻辑或,任何一个表达式的值为 YES,即为 YES。
NOT,!:逻辑非,对原有的表达式 结果取反。

字符串比较运算符

  • BEGINSWITH、ENDSWITH、CONTAINS 分别表示是否以某字符串开头、结尾、包含。
    他们可以与c、d 连用,表示是否忽略大小写、是否忽略重音字母(字母上方有声调标号)。
    例:
    @"name BEGINSWITH[cd] 'He'"
    判断name 是否以He 开头,并且忽略大小写、忽略重音字母。 LIKE 运算符:
  • LIKE 使用?表示一个字符,*表示多个字符,也可以与c、d 连用。
    例:@”name LIKE ‘???er*’” 与Paper Plane 相匹配。
  • MATCHES:检查某个字符串是否匹配指定的正则表达式。虽然正则表达式的功能是最强大的,但执行效率也是最低的。——因此 ,前面的运算符能搞定的,就没必要用MATCHES运算符。

操作集合的运算符 (Aggregate Operations)

  • ANY,SOME:指定只要集合中任意一个元素满足条件,即可返回 YES。

    官方文档解释 :Specifies any of the elements in the following expression. For exampleANY children.age < 18.

  • ALL:指定集合所有元素满足条件,返回 YES。

    Specifies all of the elements in the following expression. For exampleALL children.age < 18.

  • NONE:指定集合中没有元素满足条件,返回 YES。等价于NOT (ANY …).

    Specifies none of the elements in the following expression. For example,NONE children.age < 18. This is logically equivalent(逻辑等价) to NOT (ANY …).

  • IN :相当于一个SQL操作,只有左边的内容出现在右边的集合中才会返回 YES。For example, name IN { 'Ben', 'Melissa', 'Nick' } ,name 为IN右边之一才会返回 YES。

  • array[index]——返回数组中 index 索引处的元素
    Specifies the element at the specified index in the array array.
  • array[FIRST]——返回数组中第一个元素
    Specifies the first element in the array array.
  • array[LAST]——返回数组中最后一个元素
    Specifies the last element in the array array.
  • array[SIZE]——返回数组中元素的个数
    Specifies the size of the array array.

直接量

在谓词表达式 中,使用单引号和使用双引号的作用是相同的。——BUT,单引号只能用单引号结束,双引号只能用双引号结束。

谓词表达式中可以使用的直接量:
1. FALSE,NO:代表逻辑假。
2. TRUE,YES:代表逻辑真
3. NULL,NIL:代表一个空值
4. SELF:代表正在被判断的对象本身
5. “TEXT”或’text’:代表字符串
6. 数组:数组元素以英文逗号隔开,For example,{ 'comma', 'separated', 'literal', 'array' }.
7. 数值直接量:包括整数,小数和科学计数法表示形式。
8. 十六进制数: 以 0x 开头。
9. 八进制数:以0o 开头。
10. 二进制数:以0b 开头。

保留字

AND, OR, IN, NOT, ALL, ANY, SOME, NONE, LIKE, CASEINSENSITIVE, CI, MATCHES, CONTAINS, BEGINSWITH, ENDSWITH, BETWEEN, NULL, NIL, SELF, TRUE, YES, FALSE, NO, FIRST, LAST, SIZE, ANYKEY, SUBQUERY, CAST, TRUEPREDICATE, FALSEPREDICATE, UTI-CONFORMS-TO, UTI-EQUALS

0 0
原创粉丝点击