如何使 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 方法中获取浮点数?

如何从 NativeScript 调用 Objective-C NSExpression(format: ....)?

使用“现在”的 NSExpression 函数