Objective C NSPredicate 两个属性之和

Objective C NSPredicate sum of two properties

我正在尝试创建一个 NSPredicate,它可以计算两个属性的总和并将其与对象的另一个 属性 进行比较:

对象.属性1 + 对象.属性2 < 对象.属性3

我尝试了 (%K + %K) < %K 但没有成功。

PS:即使某些属性为空也应该工作。

我尽量避免使用大量复合谓词。

谢谢, 弗罗林

NSPredicate *p = [NSPredicate predicateWithFormat:
                  @"(%K==nil AND %K==nil AND %K!=nil AND 0 < %K) OR"
                   "(%K==nil AND %K==nil AND %K!=nil AND %K < 0) OR"
                   "(%K==nil AND %K==nil AND %K!=nil AND %K < 0) OR"

                   "(%K==nil AND %K!=nil AND %K!=nil AND %K < %K) OR"
                   "(%K==nil AND %K!=nil AND %K!=nil AND %K < %K) OR"
                   "(%K==nil AND %K!=nil AND %K!=nil AND (%K + %K) < 0) OR"

                   "(%K!=nil AND %K!=nil AND %K!=nil AND (%K + %K < %K))",

                   @"property1",@"property2",@"property3",@"property3",
                   @"property3",@"property1",@"property2",@"property2",
                   @"property3",@"property2",@"property1",@"property1",

                   @"property1",@"property2",@"property3",@"property2",@"property3",
                   @"property2",@"property1",@"property3",@"property1",@"property3",
                   @"property3",@"property1",@"property2",@"property1",@"property2",

                   @"property1",@"property2",@"property3",@"property1",@"property2",@"property3"
                   ];

假设您使用的是 SQLite 持久存储,提取谓词将转换为等效的 SQLite WHERE 子句。因此,NULL 值的处理由 SQLite 决定。来自 SQLite documentation:

Adding anything to null gives null

因此,如果谓词中的任何属性为 NULL,则总和将为 NULL。 Predicate Programming Guide 也明确指出必须单独测试 NULL 值:

A comparison predicate does not match any value with null except null (nil) or the NSNull null value .... If you want to match null values, you must include a specific test in addition to other comparisons ...

因此,正如@Kamil.S 在他的回答中所做的那样,您将不得不在谓词中显式测试空值。有一种方法可以让它更容易阅读和处理:用条件表达式(相当于 property1 == nil ? 0 : property1)替换 属性 值。您可以使用 NSExpression (see documentation):

NSExpression *prop1 = [NSExpression expressionForConditional:[NSPredicate predicateWithFormat:@"property1 == nil"] 
                                    trueExpression: [NSExpression expressionForConstantValue: @0] 
                                    falseExpression: [NSExpression expressionForKeyPath:@"property1"]];

property2 也类似)。然后,您可以使用 %@ 格式说明符将这些 NSExpression 值替换到您的谓词中:

fetch.predicate = [NSPredicate predicateWithFormat:@"%@ + %@ < %@", prop1, prop2, prop3];

CoreData 将条件表达式解析为 SQLite CASE (...) when 1 then (...) else (...) END 子句,该子句在数据库中作为提取的一部分进行评估:但我不知道与冗长的复合谓词相比性能如何。 (我也只使用单个条件表达式进行了测试;我假设 CoreData 可以在单个谓词中处理两个或更多个,但留待您确认。)