I have a view where I would like to get an average value of a "percentage" property without loading all the objects (and their other properties) into memory from Core Data. I have found out how to do this in Apple's docs, but the problem is I would like to limit the objects whose percentages are being averaged to ones that have another property called "numberAsked" greater than 0. I thought this was something I could do with an NSPredicate.
Here is what I have:
NSFetc开发者_开发百科hRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Statistics" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"numberAsked > 0"];
[request setPredicate:searchPredicate];
[request setResultType:NSDictionaryResultType];
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"percentCorrect"];
NSExpression *averagePercentExpression = [NSExpression expressionForFunction:@"average:"
arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:@"averagePercentageCorrect"];
[expressionDescription setExpression:averagePercentExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
NSError *error;
NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error];
What happens is that it seems to fetch all objects and ignore the NSPredicate. I don't know if changing the request's result type does something to this, or I need to filter the objects with another NSExpression, or what.
My testing values are that right now all objects have the numberAsked property set to 0, so theoretically my final objects array should have a count of 0, from where I would specify "N/A" for the percentage. But that is not happening.
I appreciate any help!
You can't pass an expression to setPropertiesToFetch:
. It expects an array of NSPropertyDescription
objects. Im kind of surprised it didn't crash.
You want something like this:
NSManagedObject *mo;
for (int i=0; i<5; i++) {
mo=[NSEntityDescription insertNewObjectForEntityForName:@"Test" inManagedObjectContext:self.moc];
[mo setValue:[NSNumber numberWithInt:i] forKey:@"numAttrib" ];
}
[self saveContext];
NSFetchRequest *fetch=[[NSFetchRequest alloc] init];
NSEntityDescription *testEntity=[NSEntityDescription entityForName:@"Test" inManagedObjectContext:self.moc];
[fetch setEntity:testEntity];
NSDictionary *propDict=[testEntity propertiesByName];
[fetch setPropertiesToFetch:[NSArray arrayWithObject:[propDict valueForKey:@"numAttrib"]]];
NSArray *fetchReturn=[self performFetch:fetch];//<-- my custom boilerplate
NSLog(@"fetchReturn=%@",fetchReturn);
id theAvg=[fetchReturn valueForKeyPath:@"@avg.numAttrib"];
NSLog(@"theAvg=%f",[theAvg floatValue]);
... which prints:
fetchReturn=(
"<NSManagedObject: 0x5d2fae0> (entity: Test; id: 0x5d0c310 <x-coredata://384EFAF2-1921-4CB0-85B2-402DBA145615/Test/p1> ; data: {\n numAttrib = 3;\n})",
"<NSManagedObject: 0x5d35df0> (entity: Test; id: 0x5d34480 <x-coredata://384EFAF2-1921-4CB0-85B2-402DBA145615/Test/p2> ; data: {\n numAttrib = 1;\n})",
"<NSManagedObject: 0x5d33890> (entity: Test; id: 0x5d31810 <x-coredata://384EFAF2-1921-4CB0-85B2-402DBA145615/Test/p3> ; data: {\n numAttrib = 2;\n})",
"<NSManagedObject: 0x5d36d10> (entity: Test; id: 0x5d0dfa0 <x-coredata://384EFAF2-1921-4CB0-85B2-402DBA145615/Test/p4> ; data: {\n numAttrib = 4;\n})",
"<NSManagedObject: 0x5d38f00> (entity: Test; id: 0x5d302a0 <x-coredata://384EFAF2-1921-4CB0-85B2-402DBA145615/Test/p5> ; data: {\n numAttrib = 0;\n})"
)
theAvg=2.000000
If you want to go even lighter weight. You can add:
[fetch setResultType:NSDictionaryResultType];
... which returns an array of single key dictionaries which like so:
fetchReturn=(
{
numAttrib = 2;
},
{
numAttrib = 0;
},
{
numAttrib = 4;
},
{
numAttrib = 1;
},
{
numAttrib = 3;
}
)
float=2.000000
精彩评论