【问题标题】:Predicate to compare object with each other object in the same collection谓词将对象与同一集合中的其他对象进行比较
【发布时间】:2012-11-04 16:12:34
【问题描述】:

我有一个 NSArray 的日历周期,它由 NSManagedObjects 组成,其模型如下图所示:

具有以下示例内容:

endMonth = 9;
endYear = 2012;
length = 3;
...

我想做的事:

我正在尝试构建一个谓词,该谓词仅返回存在一年前等效期间的日历期间。示例:仅当数组中有句点 2011, 9, 3 时,才返回句点 2012, 9, 3(年、月、长度)作为结果。谓词需要将每个日历周期与数组中的每个日历周期进行比较。

这是我尝试过的谓词:

predicate = [NSPredicate predicateWithFormat:
       @"SUBQUERY(SELF, $x, $x.endYear == endYear - 1 "
        "AND $x.endMonth == endMonth AND $x.length = length).@count > 0"];

问题:

但是,使用此谓词运行我的应用程序会导致运行时崩溃并显示错误消息:NSInternalInconsistencyException',原因:'无法使用非集合对象执行集合评估。'

我的谓词有什么问题,我需要如何正确指定它?

谢谢!

【问题讨论】:

标签: objective-c ios core-data nspredicate


【解决方案1】:

首先,解决您看到的错误。这是你的谓词:

[NSPredicate predicateWithFormat:@"SUBQUERY(SELF, $x, $x.endYear == endYear - 1 "
    "AND $x.endMonth == endMonth AND $x.length = length).@count > 0"]

SUBQUERY 表达式的第一个参数是 SUBQUERY 将迭代的集合。因此,您期望SELF 评估为NSArrayNSSet。但是,您在子查询谓词中使用键路径endYearendMonthlength 似乎表明您期望SELF 评估为CalendarPeriod。因此,SELF 是一个集合(endYearendMonthlength 是该集合的无效键路径),或者 SELF 是一个 CalendarPeriod(因此不能用作SUBQUERY的收藏。根据你的错误,应该是后者。

如果我们要写出您的问题(不使用NSPredicate),我们可能会得到这样的结果:

NSArray *calendarPeriods = ...;
for (CalendarPeriod *period in calendarPeriods) {
  for (CalendarPeriod *otherPeriod in calendarPeriods) {
    if ([otherPeriod endYear] == [period endYear] - 1 && [otherPeriod endMonth] == [period endMonth] && [otherPeriod length] == [period length]) {
      return YES;
    }
  }
}
return NO;

那么,如何复制这个...

您最初的尝试似乎相当不错。我认为唯一需要做的改变是,你应该使用%@,而不是SELF 作为SUBQUERY 的第一个参数,以及calendarPeriods 集合中的替代品。或者,如果您将其作为NSFetchRequest 的谓词执行,您可以尝试使用FETCH() 表达式来获取每个CalendarPeriod 对象。

顺便说一句,如果你走这条路,你的表现会很差。这是一个有保证的 O(N2),你可以做得更好。例如,如果您将每个CalendarPeriod 提取到内存中,然后将它们插入到由endYearendMonthlength 组合键控的NSDictionary 中,那么您可以将其缩减为O( N) 时间。

【讨论】:

  • 感谢您非常全面的回答,Dave。我有两个后续问题:1:当我在SUBQUERY 中替换SELFby %@ 时,我需要指定什么作为获取请求的参数(因为CalendarPeriodNSManagedObject,我通过NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"CalendarPeriod"]获取)。 2:我在哪里可以找到有关您建议的FETCH()expression 的更多信息。这种表达方式对我来说很新鲜。
猜你喜欢
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多