`
慭慭流觞
  • 浏览: 45584 次
  • 性别: Icon_minigender_1
  • 来自: 河南
社区版块
存档分类
最新评论

NSPredicate

    博客分类:
  • iOS
阅读更多

NSPredicate is a Foundation class that specifies how data should be fetched or filtered. Its query language, which is like a cross between a SQL WHERE clause and a regular expression, provides an expressive, natural language interface to define logical conditions on which a collection is searched.

It's easier to show NSPredicate in use, rather than talk about it in the abstract, so we're going to revisit the example data set used in the NSSortDescriptor article:

index 0 1 2 3
firstName Alice Bob Charlie Quentin
lastName Smith Jones Smith Alberts
age 24 27 33 31
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property NSNumber *age;
@end

@implementation Person

- (NSString *)description {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}

@end

#pragma mark -

NSArray *firstNames = @[ @"Alice", @"Bob", @"Charlie", @"Quentin" ];
NSArray *lastNames = @[ @"Smith", @"Jones", @"Smith", @"Alberts" ];
NSArray *ages = @[ @24, @27, @33, @31 ];

NSMutableArray *people = [NSMutableArray array];
[firstNames enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    Person *person = [[Person alloc] init];
    person.firstName = firstNames[idx];
    person.lastName = lastNames[idx];
    person.age = ages[idx];
    [people addObject:person];
}];

NSPredicate *bobPredicate = [NSPredicate predicateWithFormat:@"firstName = 'Bob'"];
NSPredicate *smithPredicate = [NSPredicate predicateWithFormat:@"lastName = %@", @"Smith"];
NSPredicate *thirtiesPredicate = [NSPredicate predicateWithFormat:@"age >= 30"];

// ["Bob Jones"]
NSLog(@"Bobs: %@", [people filteredArrayUsingPredicate:bobPredicate]);

// ["Alice Smith", "Charlie Smith"]
NSLog(@"Smiths: %@", [people filteredArrayUsingPredicate:smithPredicate]);

// ["Charlie Smith", "Quentin Alberts"]
NSLog(@"30's: %@", [people filteredArrayUsingPredicate:thirtiesPredicate]);

Using NSPredicate with Collections

Foundation provides methods to filter NSArray / NSMutableArray & NSSet / NSMutableSet with predicates.

Immutable collections, NSArray & NSSet, have the methods filteredArrayUsingPredicate: and filteredSetUsingPredicate: which return an immutable collection by evaluating a predicate on the receiver.

Mutable collections, NSMutableArray & NSMutableSet have the method filterUsingPredicate:, which removes any objects that evaluate to FALSE when running the predicate on the receiver.

NSDictionary can use predicates by filtering its keys or values (both NSArray objects). NSOrderedSet can either create new ordered sets from a filtered NSArray or NSSet, or alternatively, NSMutableSet can simply removeObjectsInArray:, passing objects filtered with the negated predicate.

Using NSPredicate with Core Data

NSFetchRequest has a predicate property, which specifies the logical conditions under which managed objects should be retrieved. The same rules apply, except that predicates are evaluated by the persistent store coordinator within a managed object context, rather than collections being filtered in-memory.

Predicate Syntax

Substitutions

  • %@ is a var arg substitution for an object value—often a string, number, or date.
  • %K is a var arg substitution for a key path.
NSPredicate *ageIs33Predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"age", @33];

// ["Charlie Smith"]
NSLog(@"Age 33: %@", [people filteredArrayUsingPredicate:ageIs33Predicate]);
  • $VARIABLE_NAME is a value that can be substituted with NSPredicate -predicateWithSubstitutionVariables:.
NSPredicate *namesBeginningWithLetterPredicate = [NSPredicate predicateWithFormat:@"(firstName BEGINSWITH[cd] $letter) OR (lastName BEGINSWITH[cd] $letter)"];

// ["Alice Smith", "Quentin Alberts"]
NSLog(@"'A' Names: %@", [people filteredArrayUsingPredicate:[namesBeginningWithLetterPredicate predicateWithSubstitutionVariables:@{@"letter": @"A"}]]);

Basic Comparisons

  • =, ==: The left-hand expression is equal to the right-hand expression.
  • >=, =>: The left-hand expression is greater than or equal to the right-hand expression.
  • <=, =<: The left-hand expression is less than or equal to the right-hand expression.
  • >: The left-hand expression is greater than the right-hand expression.
  • <: The left-hand expression is less than the right-hand expression.
  • !=, <>: The left-hand expression is not equal to the right-hand expression.
  • BETWEEN: The left-hand expression is between, or equal to either of, the values specified in the right-hand side. The right-hand side is a two value array (an array is required to specify order) giving upper and lower bounds. For example, 1 BETWEEN { 0 , 33 }, or $INPUT BETWEEN { $LOWER, $UPPER }.

Basic Compound Predicates

  • AND, &&: Logical AND.
  • OR, ||: Logical OR.
  • NOT, !: Logical NOT.

String Comparisons

String comparisons are by default case and diacritic sensitive. You can modify an operator using the key characters c and d within square braces to specify case and diacritic insensitivity respectively, for example firstName BEGINSWITH[cd] $FIRST_NAME.

  • BEGINSWITH: The left-hand expression begins with the right-hand expression.
  • CONTAINS: The left-hand expression contains the right-hand expression.
  • ENDSWITH: The left-hand expression ends with the right-hand expression.
  • LIKE: The left hand expression equals the right-hand expression: ? and * are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters.
  • MATCHES: The left hand expression equals the right hand expression using a regex-style comparison according to ICU v3 (for more details see the ICU User Guide for Regular Expressions).

Aggregate Operations

Relational Operations

  • ANY, SOME: Specifies any of the elements in the following expression. For example, ANY children.age < 18.
  • ALL: Specifies all of the elements in the following expression. For example, ALL children.age < 18.
  • NONE: Specifies none of the elements in the following expression. For example, NONE children.age < 18. This is logically equivalent to NOT (ANY ...).
  • IN: Equivalent to an SQL IN operation, the left-hand side must appear in the collection specified by the right-hand side. For example, name IN { 'Ben', 'Melissa', 'Nick' }.

Array Operations

  • array[index]: Specifies the element at the specified index in array.
  • array[FIRST]: Specifies the first element in array.
  • array[LAST]: Specifies the last element in array.
  • array[SIZE]: Specifies the size of array.

Boolean Value Predicates

  • TRUEPREDICATE: A predicate that always evaluates to TRUE.
  • FALSEPREDICATE: A predicate that always evaluates to FALSE.

NSCompoundPredicate

We saw that AND & OR can be used in predicate format strings to create compound predicates. However, the same can be accomplished using an NSCompoundPredicate.

For example, the following predicates are equivalent:

[NSCompoundPredicate andPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"age > 25"], [NSPredicate predicateWithFormat:@"firstName = %@", @"Quentin"]]];

[NSPredicate predicateWithFormat:@"(age > 25) AND (firstName = %@)", @"Quentin"];

While the syntax string literal is certainly easier to type, there are occasions where you may need to combine existing predicates. In these cases, NSCompoundPredicate -andPredicateWithSubpredicates: & -orPredicateWithSubpredicates: is the way to go.

NSComparisonPredicate

Similarly, if after reading last week's article you now find yourself with more NSExpression objects than you know what to do with, NSComparisonPredicate can help you out.

Like NSCompoundPredicate, NSComparisonPredicate constructs an NSPredicate from subcomponents—in this case, NSExpressions on the left and right hand sides. Analyzing its class constructor provides a glimpse into the way NSPredicate format strings are parsed:

+ (NSPredicate *)predicateWithLeftExpression:(NSExpression *)lhs
                             rightExpression:(NSExpression *)rhs
                                    modifier:(NSComparisonPredicateModifier)modifier
                                        type:(NSPredicateOperatorType)type
                                     options:(NSUInteger)options

Parameters

  • lhs: The left hand expression.
  • rhs: The right hand expression.
  • modifier: The modifier to apply. (ANY or ALL)
  • type: The predicate operator type.
  • options: The options to apply. For no options, pass 0.

NSComparisonPredicate Types

enum {
   NSLessThanPredicateOperatorType = 0,
   NSLessThanOrEqualToPredicateOperatorType,
   NSGreaterThanPredicateOperatorType,
   NSGreaterThanOrEqualToPredicateOperatorType,
   NSEqualToPredicateOperatorType,
   NSNotEqualToPredicateOperatorType,
   NSMatchesPredicateOperatorType,
   NSLikePredicateOperatorType,
   NSBeginsWithPredicateOperatorType,
   NSEndsWithPredicateOperatorType,
   NSInPredicateOperatorType,
   NSCustomSelectorPredicateOperatorType,
   NSContainsPredicateOperatorType,
   NSBetweenPredicateOperatorType
};
typedef NSUInteger NSPredicateOperatorType;

NSComparisonPredicate Options

  • NSCaseInsensitivePredicateOption: A case-insensitive predicate. You represent this option in a predicate format string using a [c] following a string operation (for example, "NeXT" like[c] "next").
  • NSDiacriticInsensitivePredicateOption: A diacritic-insensitive predicate. You represent this option in a predicate format string using a [d] following a string operation (for example, "naïve" like[d] "naive").
  • NSNormalizedPredicateOption: Indicates that the strings to be compared have been preprocessed. This option supersedes NSCaseInsensitivePredicateOption and NSDiacriticInsensitivePredicateOption, and is intended as a performance optimization option. You represent this option in a predicate format string using a [n] following a string operation (for example, "WXYZlan" matches[n] ".lan").
  • NSLocaleSensitivePredicateOption: Indicates that strings to be compared using <, <=, =, =>, > should be handled in a locale-aware fashion. You represent this option in a predicate format string using a [l] following one of the <, <=, =, =>, > operators (for example, "straße" >[l] "strasse").

Block Predicates

Finally, if you just can't be bothered to learn the NSPredicate format syntax, you can go through the motions with NSPredicate +predicateWithBlock:.

NSPredicate *shortNamePredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
            return [[evaluatedObject firstName] length] <= 5;
        }];

// ["Alice Smith", "Bob Jones"]
NSLog(@"Short Names: %@", [people filteredArrayUsingPredicate:shortNamePredicate]);

...Alright, that whole dig on predicateWithBlock: as being the lazy way out wasn't entirely charitable.

Actually, since blocks can encapsulate any kind of calculation, there is a whole class of queries that can't be expressed with the NSPredicate format string (such as evaluating against values dynamically calculated at run-time). And while its possible to accomplish the same using an NSExpression with a custom selector, blocks provide a convenient interface to get the job done.

One important note: NSPredicates created with predicateWithBlock: cannot be used for Core Data fetch requests backed by a SQLite store.


NSPredicate is, and I know this is said a lot, truly one of the jewels of Cocoa. Other languages would be lucky to have something with half of its capabilities in a third-party library—let alone the standard library. Having it as a standard-issue component affords us as application and framework developers an incredible amount of leverage in working with data.

Together with NSExpression, NSPredicate reminds us what a treat Foundation is: a framework that is not only incredibly useful, but meticulously architected and engineered, to be taken as inspiration for how we should write our own code.

 
分享到:
评论

相关推荐

    NSpredicate

    `NSPredicate`是Objective-C和Swift中用于创建查询表达式的一个类,它是Core Foundation框架的一部分,主要用于过滤数据集合,如数组、字典或集合。它允许我们基于特定条件对数据进行筛选,而无需显式的循环操作,...

    NSPredicate模糊搜索(全方面搜索)支持中文、数字、字母

    在iOS开发中,NSPredicate是Objective-C中的一个强大的类,用于构建查询表达式,它可以用于在数组、集合或Core Data上下文中执行复杂的过滤操作。在本案例中,我们关注的是NSPredicate在实现模糊搜索,特别是支持...

    Swift_NSPredicate模糊、精确、查找Demo

    在iOS开发中,Swift语言是苹果官方推荐的编程语言,而`NSPredicate`是Objective-C中的一个类,但在Swift中同样可以使用。`NSPredicate`主要用于数据过滤和查询,它支持模糊查询、精确匹配以及复杂条件的组合,是Core...

    ios-NSPredicate用于查询.zip

    在iOS开发中,数据管理是不可或缺的一部分,而`NSPredicate`是Apple的Cocoa框架提供的一种强大工具,用于处理和过滤数据。它的工作原理类似于SQL中的`WHERE`子句,可以对数组或集合进行筛选,以获取满足特定条件的...

    NSPredicate Demo

    在iOS和macOS开发中,`NSPredicate`是Foundation框架中的一个重要组件,它主要用于数据查询和过滤。这个“NSPredicate Demo”很可能是演示了如何利用`NSPredicate`进行数据筛选和检索的实例。`NSPredicate`是...

    NSPredicate用法

    本demo详细讲解了NSPredicate的使用;例如正则表达的使用、把程序中的一个数组中符合数组中内容的元素过滤出来、其它字符串的使用 BEGINSWITH、ENDSWITH、CONTAINS IN、BETWEEN、和match混合使用 比较问题

    iOS中NSPredicate谓词的使用

    在iOS开发中,NSPredicate是Objective-C和Swift中用于数据查询和过滤的重要工具。它允许开发者根据特定条件筛选集合中的对象,例如数组或字典,而无需使用传统的循环和条件语句。本篇文章将深入探讨NSPredicate的...

    IOS中NSPredicate和NSRegularExpression校验正则表达式区别

    IOS中NSPredicate和NSRegularExpression校验正则表达式区别 NSPredicate和NSRegularExpression是iOS开发中两种常用的正则表达式校验方式,它们都可以用来校验字符串是否匹配某个模式,但是它们之间存在一些区别。 ...

    iOS中谓词(NSPredicate)的基本入门使用教程

    在iOS开发中,NSPredicate是Objective-C和Swift中用于数据查询和过滤的强大工具。它允许开发者根据特定的逻辑条件对数组、数据库记录等进行筛选。本文将深入介绍NSPredicate的基本用法,帮助初学者掌握这一核心概念...

    30分钟快速带你理解iOS中的谓词NSPredicate

    谓词NSPredicate是iOS开发中用于定义数据筛选条件的关键类,它基于Cocoa框架,能够帮助开发者高效地从集合中筛选符合特定条件的对象。在本文中,我们将深入探讨NSPredicate的使用方法,包括其基本概念、分类以及在...

    PredicateFlow:编写出色,强类型且易于阅读的NSPredicate

    编写惊人的,类型强且易于阅读的NSPredicate。 该库允许您编写可流动的NSPredicate,而无需猜测属性名称,谓词操作或编写错误的参数类型。 支持平台 iOS 9.0以上 macOS 10.9以上 tvOS 9.0以上 watchOS 2.0+ 安装 ...

    PredicateKit是NSPredicate的替代产品,使您可以为CoreData编写表达性和类型安全的谓词-Swift开发

    PredicateKit是NSPredicate的替代产品,使您可以使用键路径,比较和逻辑运算符,文字值和函数为CoreData编写表达性和类型安全的谓词。 :bullseye:PredicateKit PredicateKit是NSPredicate的替代产品,使您可以使用键...

    模糊搜索DEMO

    本DEMO是关于如何实现模糊搜索的一个示例,通过解析提供的`NSPredicate_Demo`文件,我们可以深入理解这一技术。 `NSPredicate`是苹果iOS和macOS平台上的一个强大的查询对象,它是基于Core Foundation框架的`...

    正则表达式例子

    在Cocoa中,`NSPredicate`提供了一种类似SQL查询的方式来描述查询条件,如`BETWEEN`、`IN`、`BEGINWITH`、`ENDWITH`、`CONTAINS`和`LIKE`等,使得数据筛选和匹配变得更加直观和高效。 总结起来,正则表达式是编程中...

    正则表达式判断手机号码

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexString]; BOOL isValid = [predicate evaluateWithObject:phoneNumber]; if (isValid) { NSLog(@"手机号码合法"); } else { ...

Global site tag (gtag.js) - Google Analytics