Joshua
Joshua

Reputation: 197

NSPredicate for multiple matches in NSFetchRequest

First off: sorry if the title isn't very clear, I couldn't quite put my question into short words!

Please consider the following scenario:
- You are using Core Data for storing objects
- You want to fetch objects from your context
- You want to include a predicate to only fetch objects with certain properties
- You have an NSDictionary containing key-value pairs where the key represents the property name and the value represents the desired value to match against

How is best to achieve this?

I currently have the following, which is a quick and probably inefficient way of achieving this:

NSDictionary *attributes = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects:@"value1", @"value2", nil] forKeys: [NSArray arrayWithObjects:@"attr1", @"attr2", nil] ];

// Build predicate format
NSString *predicate = @"";
NSMutableArray *predicateArguments = [[NSMutableArray alloc] init];
int index = 0;
for (NSString *key in attributes) {
    NSString *value = [attributes objectForKey: key];
    predicate = [predicate stringByAppendingFormat: @"(%@ = %@) %@", key, @"%@", index == [attributes count]-1 ? @"" : @"AND "];
    [predicateArguments addObject: value];
    index++;
}

NSPredicate *matchAttributes = [NSPredicate predicateWithFormat:predicate argumentArray:predicateArguments];

--

Is there a shorter or more efficient way of achieving this predicate?

Please be aware that block predicates are not an option due to not being supported with NSFetchRequest (Core Data)

Upvotes: 2

Views: 1273

Answers (1)

Martin R
Martin R

Reputation: 539955

A slightly shorter and perhaps more elegant way is to use a NSCompoundPredicate:

NSDictionary *attributes = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects:@"value1", @"value2", nil] forKeys: [NSArray arrayWithObjects:@"attr1", @"attr2", nil] ];

// Build array of sub-predicates:
NSMutableArray *subPredicates = [[NSMutableArray alloc] init];
for (NSString *key in attributes) {
    NSString *value = [attributes objectForKey: key];
    [subPredicates addObject:[NSPredicate predicateWithFormat:@"%K = %@", key, value]];
}
// Combine all sub-predicates with AND:
NSPredicate *matchAttributes = [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];

ADDED: Even better (thanks to Paul.s):

NSMutableArray *subPredicates = [[NSMutableArray alloc] init];
[attributes enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
    [subPredicates addObject:[NSPredicate predicateWithFormat:@"%K = %@", key, value]];
}];
NSPredicate *matchAttributes = [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];

Upvotes: 4

Related Questions