XSLT存档  

不及格的程序员-八神

 查看分类:  ASP.NET XML/XSLT JavaScripT   我的MSN空间Blog

Predicate

SELF

Represents the object being evaluated.


CORE DATA

Retrieving Specific Objects

If your application uses multiple contexts and you want to test whether an object has been deleted from a persistent store, you can create a fetch request with a predicate of the form self == %@. The object you pass in as the variable can be either a managed object or a managed object ID, as in the following example:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
    [NSEntityDescription entityForName:@"Employee"
            inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
 
NSPredicate *predicate =
    [NSPredicate predicateWithFormat:@"self == %@", targetObject];
[request setPredicate:predicate];
 
NSError *error;
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
if (array != nil) {
    NSUInteger count = [array count]; // May be 0 if the object has been deleted.
    //
}
else {
    // Deal with error.
}

The count of the array returned from the fetch will be 0 if the target object has been deleted. If you need to test for the existence of several objects, it is more efficient to use the IN operator than it is to execute multiple fetches for individual objects, for example:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self IN %@",
                                            arrayOfManagedObjectIDs];

 

NSPredicate

 

大家在平常的开发过程中多多少少都会接触到数据筛选,那势必会用到NSPredicate,这个类和我上一篇博文中提到的valueForKeyPath一样很强大。它的使用主要集中在两个方法中

NSArray

- (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate;

NSMutableArray

- (void)filterUsingPredicate:(NSPredicate *)predicate;

还有NSSetNSMutableSet也可以用这个类筛选。

下面我就来一一介绍这个类的用法,相信大家看完后会和我一样认为这个类真的很强大。

筛选用法

  • 利用成员实例方法
    筛选出长度大于3的字符串
    NSArray *array = @[@"jim", @"cook", @"jobs", @"sdevm"];
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"length > 3"];
    NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);

打印

(
    cook,
    jobs,
    sdevm
)

lenght就是对数组成员执行[xxxx lenght]然后判断返回的NSUInteger值是否大于3。扩展到NSString其他方法比如integerValue

NSArray *array = @[@"2", @"3", @"4", @"5"];
NSPredicate *pre = [NSPredicate predicateWithFormat:@"integerValue >= %@", @3];
NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);

如果我不想用任何实例方法,想筛选成员本身应该怎么做呢。这时候就可以用self来代替

NSPredicate *pre = [NSPredicate predicateWithFormat:@"self CONTAINS %@", @3];

CONTAINS用法后面会讲到

再扩展到模型

Test.h

@interface Test : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSNumber *code;

@end

    Test *test1 = [[Test alloc]init];
    test1.name = @"西湖";
    test1.code = @1;

    Test *test2 = [[Test alloc]init];
    test2.name = @"西溪湿地";
    test2.code = @2;

    Test *test3 = [[Test alloc]init];
    test3.name = @"灵隐寺";
    test3.code = @3;

    NSArray *array = @[test1, test2, test3];
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"code >= %@", @2];
    NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);

筛选出数组成员[test code]方法(code属性的get方法)返回值>=2的成员。这里的比较运算符同样也可以使用==!=<=<

其实==不仅可以用来比较NSNumber对象,还可以用来判断NSString对象是否相同。

NSPredicate *pre = [NSPredicate predicateWithFormat:@"name == %@", @"西湖"];

筛选出name是"西湖"的对象数组。

  • ###NSString对象的操作
    前面提到==比较运算符可以起到- (BOOL)isEqualToString:(NSString *)aString;方法的效果,来判断字符串是否相同。那么字符串中包含某个字符串应该如何判断呢,在NSPredicate中可以用CONTAINS(大小写都可以)来表示包含关系。
 NSPredicate *pre = [NSPredicate predicateWithFormat:@"name CONTAINS %@", @"湖"];

当判断的时候需要忽略大小写可以使用[cd]

[c] 忽略大小写

[d] 忽略重音符号

[cd]既不区分大小写,也不区分发音符号。

使用:

NSPredicate *pre = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", @"abc"];

再涉及到一些更复杂的查询语句,比如判断字符串以某个字符串开头或者结尾,通配符的使用。

BEGINSWITH(已某个字符串开头, begins with)

    NSString *targetString = @"h";
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name BEGINSWITH %@",targetString];

ENDSWITH(已某个字符串结尾, ends with)

    NSString *targetString = @"ing";
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"name ENDSWITH %@",targetString];

通配符 LIKE

*代表一个或者多个或者是空

?代表一个字符

Test *test1 = [[Test alloc]init];
test1.name = @"absr";
test1.code = @1;

Test *test2 = [[Test alloc]init];
test2.name = @"asb";
test2.code = @2;

Test *test3 = [[Test alloc]init];
test3.name = @"raskj";
test3.code = @3;

NSArray *array = @[test1, test2, test3];

NSPredicate *pre = [NSPredicate predicateWithFormat:@"name LIKE %@", @"?b*"];
NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);

结果是只有test1符合,like也可以接受[cd]

NSPredicate *pre = [NSPredicate predicateWithFormat:@"name LIKE[cd] %@", @"?b*"];

关系运算,包括了INBETWEENANDORNOT

IN(之中)

NSPredicate *pre = [NSPredicate predicateWithFormat:@"code IN %@", @[@1, @3]];

判断code是否@1或者是@2,也就是是否在数组中。

OR(或,可以用||代替)

OR可以用来代替IN达到同样的效果,但是OR更灵活。

NSPredicate *pre = [NSPredicate predicateWithFormat:@"code == %@ OR code == %@ ", @1, @3];

效果和IN一样,但是OR可以判断不只一个属性

NSPredicate *pred = [NSPredicate predicateWithFormat:@"code == %@ OR name == %@ ", @1, @"asb"];

BETWEEN(之间)

通常用于判断NSNumber对象

NSPredicate *pred = [NSPredicate predicateWithFormat:@"code BETWEEN {1, 3}"];

判断code是否>=1且<=3

AND(且,可以用&&代替)

NSPredicate *pred = [NSPredicate predicateWithFormat:@"code >= %@ AND code <=%@", @1, @3];

NOT(非,可以用!代替)

NOT最常见的用法就是从一个数组中剔除另外一个数组的数据,可能有点绕,举个例子就很明朗了。

    NSArray *arrayFilter = @[@"abc1", @"abc2"];
    NSArray *arrayContent = @[@"a1", @"abc1", @"abc4", @"abc2"];
    NSPredicate *thePredicate = [NSPredicate predicateWithFormat:@"NOT (SELF in %@)", arrayFilter];
    NSLog(@"%@",[arrayContent filteredArrayUsingPredicate:thePredicate]);

打印

(
    a1,
    abc4
)

比起循环比较再加到新数组中,简单的不止一两点。

前面提到的都是用+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;方法创建,还有另一种常用的方法:+ (NSPredicate*)predicateWithBlock:(BOOL (^)(id evaluatedObject, NSDictionary *bindings))block,用Block形式创建

NSPredicate *pre = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
    Test *test = (Test *)evaluatedObject;
    if (test.code.integerValue > 2) {
        return YES;
    }
    else{
        return NO;
    }
}];

参数evaluatedObject表示数组成员,block必须返回YES或者NO,分别表示匹配还是不匹配。请忽略bindings参数,具体作用我也没搞清楚。

多重筛选

如果需要匹配数个属性的筛选,用AND或者OR来串联显然有点麻烦,NSCompoundPredicate类可以满足我们的需求,它可以将多个NSPredicate对象的组合,组合方式可以是AND或者OR

    NSPredicate *pre1 = [NSPredicate predicateWithFormat:@"code >= %@", @3];
    NSPredicate *pre2 = [NSPredicate predicateWithFormat:@"code <= %@", @2];

    //以AND形式组合
    NSPredicate *pre = [NSCompoundPredicate andPredicateWithSubpredicates:@[pre1,pre2]];
    //以OR形式组合
    NSPredicate *pre = [NSCompoundPredicate orPredicateWithSubpredicates:@[pre1, pre2]];

匹配用法

其实NSPredicate不仅可以用于筛选,还可以用来判断匹配直接返回是否符合,主要方法是- (BOOL)evaluateWithObject:(id)object;,用法:

    Test *test1 = [[Test alloc]init];
    test1.name = @"absr";
    test1.code = @1;

    NSPredicate *pres = [NSPredicate predicateWithFormat:@"code == %@", @2];
    BOOL match = [pres evaluateWithObject:test1];

当然最常用的还是配合配合正则表达式,列举几个常用的正则

是否以a开头以e结尾

    NSString *string=@"assdbfe";
    NSString *targetString=@"^a.+e$";
    NSPredicate *pres = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", targetString];
    BOOL match = [pres evaluateWithObject:string];

是否是邮箱

NSString *strRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{1,5}"; 

是否是手机号

NSString *strRegex = @"[0-9]{1,20}";  

不得不说,在利用+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;方法创建的NSPredicate对象的时候有个坑。

在某些情况下,类似于上面例子中的code字符串不是很明确,创建的时候就会这样使用

Test *test1 = [[Test alloc]init];
test1.name = @"absr";
test1.code = @1;

Test *test2 = [[Test alloc]init];
test2.name = @"asb";
test2.code = @2;

Test *test3 = [[Test alloc]init];
test3.name = @"raskj";
test3.code = @3;

NSArray *array = @[test1, test2, test3];

NSPredicate *pre = [NSPredicate predicateWithFormat:@"%@ == %@", @"code", @2];
NSLog(@"%@", [array filteredArrayUsingPredicate:pre]);

注意NSPredicate对象的初始化方式。运行这块代码你会发现test2对象没有被查询出来。打印pre发现"code" == 2,这说明查找的是"code"方法的返回值,这显然行不通。

如果查询的是属性,比如code是Test类的属性,那么利用下面的创建方式

NSPredicate *pre = [NSPredicate predicateWithFormat:@"%K == %@", @"code", @2];

就不会被坑

注意:%KK必须是大写。

最后

NSPredicate几乎可以满足所有形式的查询,配合Core Data的数据库查询当然不在话下。NSPredicate用法不只这些,有兴趣的同学可以看下nshipster网站的这篇博文,里面提到了一些我没有涉及到的用法。

 

 
NSPredicate的用法

一般来说这种情况还是蛮多的,比如你从文件中读入了一个array1,然后想把程序中的一个array2中符合array1中内容的元素过滤出来。

正 常傻瓜一点就是两个for循环,一个一个进行比较,这样效率不高,而且代码也不好看。

其实一个循环或者无需循环就可以搞定了,那就需要用搞 NSPredicate这个类了~膜拜此类~

1)例子一,一个循环

NSArray *arrayFilter = [NSArray arrayWithObjects:@"pict", @"blackrain", @"ip", nil];

NSArray *arrayContents = [NSArray arrayWithObjects:@"I am a picture.", @"I am a guy", @"I am gagaga", @"ipad", @"iphone", nil];

我想过滤arrayContents的话只要循环 arrayFilter就好了

int i = 0, count = [arrayFilter count];

for(i = 0; i < count; i ++)

{

NSString *arrayItem = (NSString *)[arrayFilter objectAtIndex:i];

NSPredicate *filterPredicate = [[NSPredicate predicateWithFormat:@"SELF CONTAINS %@", arrayItem];

NSLog(@"Filtered array with filter %@, %@", arrayItem, [arrayContents filteredArrayUsingPredicate:filterPredicate]);

}

当然以上代码中arrayContent最好用mutable 的,这样就可以直接filter了,NSArray是不可修改的。

2)例子二,无需循环

NSArray *arrayFilter = [NSArray arrayWithObjects:@"abc1", @"abc2", nil];

NSArray *arrayContent = [NSArray arrayWithObjects:@"a1", @"abc1", @"abc4", @"abc2", nil];

NSPredicate *thePredicate = [NSPredicate predicateWithFormat:@"NOT (SELF in %@)", arrayFilter];

[arrayContent filterUsingPredicate:thePredicate];

 

这样arrayContent过滤出来的就是不包含 arrayFilter中的所有item了。

 

3)生成文件路径下文件集合列表

NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *defaultPath = [[NSBundle mainBundle] resourcePath];
    NSError *error;
    NSArray *directoryContents = [fileManager contentsOfDirectoryAtPath:defaultPath error:&error]

 

4)match的用法

    1. 简单比较

    NSString *match = @"imagexyz-999.png";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF == %@", match];
    NSArray *results = [directoryContents filteredArrayUsingPredicate:predicate];

2. match里like的用法(类似Sql中的用法)
  NSString *match = @"imagexyz*.png";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like %@", match];
    NSArray *results = [directoryContents filteredArrayUsingPredicate:predicate];
3. 大小写比较
  [c]表示忽略大小写,[d]表示忽略重音,可以在一起使用,如下:
NSString *match = @"imagexyz*.png";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like[cd] %@", match];
    NSArray *results = [directoryContents filteredArrayUsingPredicate:predicate];

4.使用正则 
NSString *match = @"imagexyz-\\d{3}\\.png";  //imagexyz-123.png
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF matches %@", match];
    NSArray *results = [directoryContents filteredArrayUsingPredicate:predicate];

总结:

1) 当使用聚合类的操作符时是可以不需要循环的

2)当使用单个比较类的操作符时可以一个循环来搞定

PS,例子 一中尝试使用[@"SELF CONTAINS %@", arrayFilter] 来过滤会挂调,因为CONTAINS时字符串比较操作符,不是集合操作符。

 

 
 
posted on 2014-08-19 09:37  不及格的程序员-八神  阅读(515)  评论(0编辑  收藏  举报