谓词将对象与同一集合中的每个其他对象进行比较

时间:2012-11-04 16:12:34

标签: objective-c ios core-data nspredicate

我有NSArray个日历期,由NSManagedObjects组成,并按照此屏幕截图显示:

CoreDataModel

包含以下示例内容:

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

我要做的是:

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

这是我试过的谓词:

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

问题:

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

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

谢谢!

1 个答案:

答案 0 :(得分:2)

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

[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是{{1} (因此不能用作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(N 2 ),你可以做得更好。例如,如果您将每个CalendarPeriod提取到内存中,然后将它们插入由NSDictionaryendYearendMonth组合键入的length中,那么你可以把它减少到O(N)时间。