Core Data has built-in support for a number of different functions – which it calls expressions – including average, sum, min, and max.
Let’s have a look at how easy it is to use them.
Suppose we have an entity called ‘Product’, and we want to retrieve the average price of all products that are currently in stock. We start off by creating our typical NSFetchRequest object.
NSFetchRequest* request = [[NSFetchRequest alloc] init]; request.entity = [NSEntityDescription entityForName:@"Product" inManagedObjectContext:myContext];
We the set up our filter, to make sure we only retrieve items that are in stock. Obviously a real application would likely have a much more complicated predicated here; this is just for demonstration purposes.
request.predicate = [NSPredicate predicateWithFormat:@"StockStatus = %@", @"InStock"];
Next, we have to specify what type of results we want to be returned. The documentation for this property doesn’t seem to be all that good, so we’ll just do what Apple says and ask for a dictionary.
request.resultType = NSDictionaryResultType;
Now we’re on to the actual average calculation code. We need to create a NSExpressionDescription as the top-level thingy that we are requesting the average with. We give it a name so that we can read it out of the dictionary that we get back.
NSExpressionDescription* averageExpressionDescription = [[NSExpressionDescription alloc] init]; [averageExpressionDescription setName:@"thisIsTheAverageThatIWant"];
Here’s where it gets a little strange. We have to give our expression description an NSExpression which specifies that we want the average (this is where’ you’d stick in “sum”, “max”, etc. if you wanted them instead). Then, we have to give that expression an NSExpression to specify what field we want to calculate the average on.
[averageExpressionDescription setExpression:[NSExpression expressionForFunction:@"average:" arguments:[NSArray arrayWithObject: [NSExpression expressionForKeyPath:@"Price"]]]];
The last thing we have to do to our expression description is set the return data type. In this case, our field is a float, so we’ll specify NSFloatAttributeType.
We then tell our original fetch request that we want to fetch the average object that we just created.
request.propertiesToFetch = [NSArray arrayWithObject:averageExpressionDescription ;
Finally, we’re ready to execute our fetch request!
NSArray* results = [myContext executeFetchRequest:request error:nil];
Remember how we specified that we wanted a dictionary above? That dictionary is inside the results array, so we’ll extract it, and then read out the value using the key that we specified earlier.
NSDictionary* fetchResultsDictionary = [results objectAtIndex:0]; double finallyIHaveTheAverage = [[fetchResultsDictionary objectForKey:@"thisIsTheAverageThatIWant"] floatValue];
And that’s all there is to it! You are now ready to go calculate averages and sums with this simple 17 step proces!
Alternately, you could just use ios-queryable, and do it in one line:
double wowThatWasEasy = [[[myContext ofType:@"Product"] where:@"StockStatus = %@", @"InStock"] average:@"Price"];