开发者

Filter setPropertiesToFetch with NSPredicate in Core Data?

开发者 https://www.devze.com 2023-01-13 23:08 出处:网络
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 d

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
0

精彩评论

暂无评论...
验证码 换一张
取 消