The relatively new
NSExpression class is incredibly powerful, yet not really used very often. Part of that is that it's not very well documented. Although the API documentation for
NSExpression is fairly well detailed, the listed "companion guide" (
Introduction to Predicates Programming) has very little information about how to actually use
NSExpression.
NSExpression deserves to be better documented, because it brings to predicate programming (including Core Data), a lot of features from the relational database world that people often complain are missing, like unioning, intersecting, and subtracting resultsets and performing aggregate operations without loading managed objects or faults into memory.
The aggregates functionality is especially important on iOS given the limited memory on most iOS devices. If you've got a large dataset, and you want to get a count of objects, or calculate an average or sum for one of the attributes, you really don't want to have to pull the entire dataset into memory. Even if they're just faults, they're going to eat up memory you don't need to use because the underlying SQLite persistent store can figure that stuff out without the object overhead.
I don't have time to do a full
NSExpression tutorial, but I thought it at least worth posting a category on
NSManagedObject that lets you take advantage of some of its more useful features.
With this category, to get a sum of the attribute
bar on entity
Foo, you would do this:
NSNumber *fooSum = [Foo aggregateOperation:@"sum:" onAttribute:@"bar" withPredicate:nil inManagedObjectContext:context];
This will calculate it for you using the database features, NOT by loading all the managed objects into memory. Much more memory and processor efficient than doing it manually.
Cheers. Category follows:
Header File:@interface NSManagedObject(MCAggregate)
+(NSNumber *)aggregateOperation:(NSString *)function onAttribute:(NSString *)attributeName withPredicate:(NSPredicate *)predicate inManagedObjectContext:(NSManagedObjectContext *)context
@end
Implementation File:+(NSNumber *)aggregateOperation:(NSString *)function onAttribute:(NSString *)attributeName withPredicate:(NSPredicate *)predicate inManagedObjectContext:(NSManagedObjectContext *)context
{
NSExpression *ex = [NSExpression expressionForFunction:function
arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:attributeName]]];
NSExpressionDescription *ed = [[NSExpressionDescription alloc] init];
[ed setName:@"result"];
[ed setExpression:ex];
[ed setExpressionResultType:NSInteger64AttributeType];
NSArray *properties = [NSArray arrayWithObject:ed];
[ed release];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setPropertiesToFetch:properties];
[request setResultType:NSDictionaryResultType];
if (predicate != nil)
[request setPredicate:predicate];
NSEntityDescription *entity = [NSEntityDescription entityForName:[self className]
inManagedObjectContext:context];
[request setEntity:entity];
NSArray *results = [context executeFetchRequest:request error:nil];
NSDictionary *resultsDictionary = [results objectAtIndex:0];
NSNumber *resultValue = [resultsDictionary objectForKey:@"result"];
return resultValue;
}
@end
11 comments:
Top quality of ecco shoes are developed for discerning customers.Enjoy a great selection of newest style.discount ecco shoes on sale,free
shipping,110% price guarantee.Top quality of ecco shoes is your best chooice
for daily life and working,sport,and so on.And hot sale now UGG Boots
.fashion on the outside,warm on the inside.
Very nice and impressive article you have posted. Its very helpful, i have read and bookmark this site and will recommend it to more other peoples.
Dissertation help
Well... round about every blog posts online don't have much originality as I found on yours.. Just keep updating much useful information so that reader like me would come back over and over again.
Dissertation help
Where are you getting className from?
Also, you are leaking memory here as you never released the request object.
Its such a nice code. Thanks for the support. I really appreciate the way you written that. iPhone iPad Application Development
Hi Jeff,
Yes I agree there is not enough documentation on NSExpression. I searched for ages. I like your using a category to access these functions as it makes the actual implementation a lot tidier.
It took me a while to figure out how to get it working and I made a couple of changes, the main one applying the category to NSString, as the entity, ultimately in the category, is created from a string.
For anybody struggling here is my changed code:
MCAggregate.h
@interface NSString(MCAggregate)
-(NSNumber *)aggregateOperation:(NSString *)function onAttribute:(NSString *)attributeName withPredicate:(NSPredicate *)predicate inManagedObjectContext:(NSManagedObjectContext *)context;
@end
MCAggregate.m
#include "MCAggregate.h"
@implementation NSString(MCAggregate)
-(NSNumber *)aggregateOperation:(NSString *)function onAttribute:(NSString *)attributeName withPredicate:(NSPredicate *)predicate inManagedObjectContext:(NSManagedObjectContext *)context
{
NSExpression *ex = [NSExpression expressionForFunction:function arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:attributeName]]];
NSExpressionDescription *ed = [[NSExpressionDescription alloc] init];
[ed setName:@"result"];
[ed setExpression:ex];
[ed setExpressionResultType:NSInteger64AttributeType];
NSArray *properties = [NSArray arrayWithObject:ed];
[ed release];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setPropertiesToFetch:properties];
[request setResultType:NSDictionaryResultType];
if (predicate != nil)
[request setPredicate:predicate];
NSEntityDescription *entity = [NSEntityDescription entityForName:self inManagedObjectContext:context];
[request setEntity:entity];
NSArray *results = [context executeFetchRequest:request error:nil];
NSDictionary *resultsDictionary = [results objectAtIndex:0];
NSNumber *resultValue = [resultsDictionary objectForKey:@"result"];
return resultValue;
}
@end
I hope this helps and thanks for the post Jeff
Barnaby
And don't forget to manage memory.
[request release]
Thanks for the nice post Jeff.
Great post!!!2945abc45 0120
canvas tote bags
Monogram Vernis
The NSExpression documentation improved nearly two weeks after you posted, see http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSExpression_Class/Reference/NSExpression.html#//apple_ref/occ/clm/NSExpression/expressionForFunction:arguments:
Post a Comment