如何使 NSExpression 的 expressionForFunction:withArguments: 尊重获取请求的谓词
Posted
技术标签:
【中文标题】如何使 NSExpression 的 expressionForFunction:withArguments: 尊重获取请求的谓词【英文标题】:How to make NSExpression's expressionForFunction:withArguments: honour the fetch request's predicate 【发布时间】:2012-12-28 18:09:28 【问题描述】:我正在使用 Core Data 来存储由值和时间戳组成的简单实体。我正在寻找一个获取请求,它返回最新添加的值,以及所有值的运行平均值。这一切似乎都很简单,直到我尝试使用 NSPredicate 将结果过滤到特定时间段内。
我正在使用 NSExpression 的 expressionForFunction:withArguments:
方法来确定平均值。通过设置启动标志-com.apple.CoreData.SQLDebug 1
,我可以清楚地看到只有最新的值符合我的日期谓词。相反,平均计算是作为子查询执行的,但没有考虑我的日期谓词:
SELECT (SELECT avg(t1.ZVALUE) FROM ZEVENT t1 WHERE t1.Z_ENT = ?), t0.ZVALUE FROM ZEVENT t0 WHERE ( t0.ZTIMESTAMP >= ? AND t0.Z_ENT = ?) ORDER BY t0.ZTIMESTAMP DESC
确定平均值的最有效(和可扩展)方法是什么,同时仍然尊重我的 NSFetchRequest 的谓词?
作为参考,这是我的完整代码:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Reading" inManagedObjectContext:moc];
[request setEntity:entity];
[request setSortDescriptors:@[sortDescriptor]];
[request setResultType:NSDictionaryResultType];
// Filter by date where necessary
NSPredicate *datePredicate = [NSPredicate predicateWithFormat:@"(timestamp >= %@)", toDate];
[request setPredicate:datePredicate];
NSExpression *valueExpression = [NSExpression expressionForKeyPath:valueKey];
NSExpressionDescription *valueDescription = [[NSExpressionDescription alloc] init];
[valueDescription setName:@"value"];
[valueDescription setExpression:valueExpression];
[valueDescription setExpressionResultType:NSDoubleAttributeType];
NSExpression *avgExpression = [NSExpression expressionForFunction:@"average:" arguments:[NSArray arrayWithObject:valueExpression]];
NSExpressionDescription *avgDescription = [[NSExpressionDescription alloc] init];
[avgDescription setName:@"averageReading"];
[avgDescription setExpression:avgExpression];
[avgDescription setExpressionResultType:NSDoubleAttributeType];
[request setPropertiesToFetch:@[avgDescription, valueDescription]];
【问题讨论】:
【参考方案1】:我看到两个错误。 toDate
没有显示初始化。我还注意到您正在传递 setPropertiesToFetch:
一个 NSExpressions 数组,但文档需要一个 NSPropertyDescriptions 数组。当您执行 fetch 请求时,我希望这种差异会导致 null 结果并填充 NSError。
你从executeFetchRequest:error:
看到了什么结果?请务必检查 NSError 结果。成语是这样的:
NSError *error;
NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
if (!results)
NSLog(@"%@ fetch error for request %@: %@ %@", fetchRequest,
error.localizedDescription, error.localizedFailureReason);
我会采取不同的方法。一个 fetch 请求的限制为 1,对timestamp
进行降序排序,并返回最新的timestamp
。如果您愿意,可以添加谓词以限制时间。然后使用第二个获取请求来计算时间戳的平均值。您甚至可以将这些调用封装到它们自己的方法中:
-(NSDate *)latestTimestamp:(NSManagedObjectContext *)moc;
-(NSNumber *)averageValueSinceTime:(NSDate *)intervalStart
context:(NSManagedObjectContext *)moc;
【讨论】:
toDate 在别处初始化(与我的 sn-p 无关)。关于setPropertiesToFetch
,我在这里关注Apple 的own suggestions。查询正确执行,我返回了一个包含请求值的数组。问题是 averageReading 显示了所有实体的总体平均值,但不尊重我的谓词。以上是关于如何使 NSExpression 的 expressionForFunction:withArguments: 尊重获取请求的谓词的主要内容,如果未能解决你的问题,请参考以下文章
从 NSExpression 捕获 NSInvalidArgumentException
如何从 NSExpression 获取 NSManagedObject?
如何使用 NSExpression 使用自定义函数设置 NSFetchRequest propertiesToFetch
如何从 NSExpression 的 expressionValueWithObject:context 方法中获取浮点数?