NSPredicate

Cocoa provides three predicate classes: NSPredicate, and two subclasses of NSPredicateNSComparisonPredicate andNSCompoundPredicate.

Dynamic Property Names

Because string variables are surrounded by quotation marks when they are substituted into a format string using %@, you cannot use%@ to specify a dynamic property name—as illustrated in the following example.

NSString *attributeName = @"firstName";
NSString *attributeValue = @"Adam";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ like %@",
        attributeName, attributeValue];

The predicate format string in this case evaluates to "firstName" like "Adam".

If you want to specify a dynamic property name, you use %K in the format string, as shown in the following fragment.

predicate = [NSPredicate predicateWithFormat:@"%K like %@",
        attributeName, attributeValue];

Creating Predicates Directly in Code

You can create predicate and expression instances directly in code. NSComparisonPredicate and NSCompoundPredicate provide convenience methods that allow you to easily create compound and comparison predicates respectively. NSComparisonPredicateprovides a number of operators ranging from simple equality tests to custom functions.

The following example shows how to create a predicate to represent (revenue >= 1000000) and (revenue < 100000000). Note that the same left-hand side expression is used for both comparison predicates.

NSExpression *lhs = [NSExpression expressionForKeyPath:@"revenue"];
 
NSExpression *greaterThanRhs = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:1000000]];
NSPredicate *greaterThanPredicate = [NSComparisonPredicate
    predicateWithLeftExpression:lhs
    rightExpression:greaterThanRhs
    modifier:NSDirectPredicateModifier
    type:NSGreaterThanOrEqualToPredicateOperatorType
    options:0];
 
NSExpression *lessThanRhs = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:100000000]];
NSPredicate *lessThanPredicate = [NSComparisonPredicate
    predicateWithLeftExpression:lhs
    rightExpression:lessThanRhs
    modifier:NSDirectPredicateModifier
    type:NSLessThanPredicateOperatorType
    options:0];
 
NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
    @[greaterThanPredicate, lessThanPredicate]];

The disadvantage of this technique should be immediately apparent—you may have to write a lot of code. The advantages are that it is less prone to spelling and other typographical errors that may only be discovered at runtime and it may be faster than depending on string parsing.

This technique is most likely to be useful when the creation of the predicate is itself dynamic, such as in a predicate builder.

Creating Predicates Using Predicate Templates

NSPredicate *predicateTemplate = [NSPredicate
    predicateWithFormat:@"lastName like[c] $LAST_NAME"];

This is equivalent to creating the variable expression directly as shown in the following example.

NSExpression *lhs = [NSExpression expressionForKeyPath:@"lastName"];
 
NSExpression *rhs = [NSExpression expressionForVariable:@"LAST_NAME"];
 
NSPredicate *predicateTemplate = [NSComparisonPredicate
    predicateWithLeftExpression:lhs
    rightExpression:rhs
    modifier:NSDirectPredicateModifier
    type:NSLikePredicateOperatorType
    options:NSCaseInsensitivePredicateOption];

To create a valid predicate to evaluate against an object, you use the NSPredicate methodpredicateWithSubstitutionVariables: to pass in a dictionary that contains the variables to be substituted. (Note that the dictionary must contain key-value pairs for all the variables specified in the predicate.)

NSPredicate *predicate = [predicateTemplate predicateWithSubstitutionVariables:
    [NSDictionary dictionaryWithObject:@"Turner" forKey:@"LAST_NAME"]];

The new predicate returned by this example is lastName LIKE[c] "Turner".

Because the substitution dictionary must contain key-value pairs for all the variables specified in the predicate, if you want to match a null value, you must provide a null value in the dictionary, as illustrated in the following example.

NSPredicate *predicate = [NSPredicate
    predicateWithFormat:@"date = $DATE"];
predicate = [predicate predicateWithSubstitutionVariables:
    [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"DATE"]];

The predicate formed by this example is date == <null>.

Format String Summary

It is important to distinguish between the different types of value in a format string. Note also that single or double quoting variables (or substitution variable strings) will cause %@%K, or $variable to be interpreted as a literal in the format string and so will prevent any substitution.

@"attributeName == %@"

This predicate checks whether the value of the key attributeName is the same as the value of the object %@ that is supplied at runtime as an argument to predicateWithFormat:. Note that %@ can be a placeholder for any object whose description is valid in the predicate, such as an instance of NSDateNSNumberNSDecimalNumber, or NSString.

@"%K == %@"

This predicate checks whether the value of the key %K is the same as the value of the object %@. The variables are supplied at runtime as arguments to predicateWithFormat:.

@"name IN $NAME_LIST"

This is a template for a predicate that checks whether the value of the key name is in the variable $NAME_LIST (no quotes) that is supplied at runtime using predicateWithSubstitutionVariables:.

@"'name' IN $NAME_LIST"

This is a template for a predicate that checks whether the constant value 'name' (note the quotes around the string) is in the variable $NAME_LIST that is supplied at runtime using predicateWithSubstitutionVariables:.

@"$name IN $NAME_LIST"

This is a template for a predicate that expects values to be substituted (using predicateWithSubstitutionVariables:) for both$NAME and $NAME_LIST.

@"%K == '%@'"

This predicate checks whether the value of the key %K is equal to the string literal “%@“ (note the single quotes around %@). The key name %K is supplied at runtime as an argument to predicateWithFormat:.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用NSPredicate的Swift代码示例,用于将大量数据按时间分组: ```swift struct DataItem { let name: String let timeStamp: TimeInterval // 时间戳 } func groupDataByTime(_ data: [DataItem]) -> [[DataItem]] { // 将数据按时间先后排序 let sortedData = data.sorted { $0.timeStamp < $1.timeStamp } // 创建空字典 var groups = [String: [DataItem]]() // 使用NSPredicate过滤并分组数据 let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" for item in sortedData { let date = Date(timeIntervalSince1970: item.timeStamp) let dateString = dateFormatter.string(from: date) let predicate = NSPredicate(format: "SELF.dateString == %@", dateString) let filteredArray = (groups as NSDictionary).filtered(using: predicate) if var items = filteredArray.first?.value as? [DataItem] { items.append(item) groups[dateString] = items } else { groups[dateString] = [item] } } // 将分组后的数据按时间先后顺序排序 let sortedGroups = groups.sorted { $0.key < $1.key } // 将所有分组添加到一个数组中 var result = [[DataItem]]() for (_, items) in sortedGroups { result.append(items) } return result } ``` 在这个示例中,我们同样定义了一个`DataItem`结构体来表示数据的名称和时间戳。`groupDataByTime`函数首先将数据按时间先后排序,然后使用`NSPredicate`过滤并分组数据。我们指定`NSPredicate`的格式为`SELF.dateString == %@`,其中`dateString`是我们根据时间戳计算得到的时间字符串,`%@`是用于替换的占位符。通过对字典进行过滤,我们可以得到一个包含指定时间字符串的数组,然后将新的数据项添加到这个数组中。最后,我们将所有分组添加到一个大数组中,按时间先后顺序排序,并返回结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值