【问题标题】:Objective C NSPredicate sum of two propertiesObjective C NSPredicate 两个属性的总和
【发布时间】:2018-07-17 22:57:55
【问题描述】:

我正在尝试创建一个 NSPredicate 可以将两个属性相加并将其与对象的另一个属性进行比较:

Object.property1 + Object.property2

我尝试了 (%K + %K)

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

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

谢谢, 弗洛林

【问题讨论】:

  • 我觉得如果加上一个计算属性会容易很多:@property (nonatomic, assign), NSIntegerOrDoubleOrWhatever property4;-(NSIntegerOrDoubleOrWhatever)property4 {return self.property1 + self.property2;},那么格式就是[NSPredicate predicateWithFormat:@"%K < %@", @"property4", @(property3)]
  • 这将是最佳的,但我当前的代码结构不支持,这是我必须做的核心数据获取。
  • stackoverflow.com/questions/34063965/… 你应该可以这样做。自从我玩 CoreData 已经有一段时间了,但答案似乎是合法的。
  • 您建议使用 Transient 属性,我已经尝试过了,但 Apple 说:“您无法使用基于瞬态属性的谓词进行获取(尽管您可以使用瞬态属性自己在内存中进行过滤)。” 《核心数据编程指南》
  • [NSPredicate predicateWithFormat:@"(%K + %K) < %K", prop1Name, prop2Name, prop3Name] 应该可以工作——你试过了吗?

标签: ios objective-c sum operators nspredicate


【解决方案1】:

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

向 null 添加任何内容都会得到 null

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

一个比较谓词不匹配任何带有 null 的值,除了 null (nil) 或 NSNull null 值...。如果要匹配 null 值,除了其他比较之外,还必须包括特定的测试...

因此,您必须在谓词中显式测试空值,正如@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 子句,该子句在数据库中作为 fetch 的一部分进行评估:但我不知道与冗长的复合谓词相比性能如何。 (我也只使用一个条件表达式进行了测试;我假设 CoreData 可以在一个谓词中处理两个或更多,但留给您确认。)

【讨论】:

  • 谢谢,这就是我要找的,正如我在第一篇文章中所说的那样,以避免产生大量复合谓词。我更改了运行测试的代码并通过了。
【解决方案2】:
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"
                   ];

【讨论】:

  • 感谢您尝试帮助我,但似乎 predicateWithBlock 不能用于核心数据,我收到一个错误:CoreData:错误:异常处理请求:,子谓词 BLOCKPREDICATE(0x10c5638c0)有问题) 与 (null) 的用户信息。更多信息在这里:stackoverflow.com/questions/3543208/…
  • 用新方法编辑了我的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-10
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
相关资源
最近更新 更多