Reputation: 2053
I have a function which fetches those objects from a particular entity that fulfill a specified criterion:
func fetchWithPredicate(entityName: String, argumentArray: [AnyObject]) -> [NSManagedObject] {
let fetchRequest = NSFetchRequest(entityName: entityName)
fetchRequest.predicate = NSPredicate(format: "%K == %@", argumentArray: argumentArray)
do {
return try self.managedContext.executeFetchRequest(fetchRequest) as! [NSManagedObject]
} catch {
let fetchError = error as NSError
print(fetchError)
return [NSManagedObject]()
}
}
When I pass an array with multiple aguments (multiple attribute names and values) it seems that creates a query like this:
attributeName1 = value1 OR attributeName2 = value2 OR attributeName3 = value3 OR...
I would like to change these ORs for ANDs.
EDIT:
The problem was that it was only replacing the first two items with "%K == %@".
So, I have to create a NSCompoundPredicate to create a predicate dynamically.
Upvotes: 11
Views: 14833
Reputation: 147
Swift 5
let predicate = NSPredicate(format: "id = %@ AND title = %@", argumentArray: ["id value", "title value"])
Upvotes: -2
Reputation: 1043
Swift 3
I found easiest way.
var predicate = NSPredicate(format: "key1 = %@ AND key2 = %@", value1, value2)
Upvotes: 6
Reputation: 17710
You could use a compound predicate. I'll give you the Objective-C syntax, I'll leave the translation to Swift as an exercise...
If your keys and values are in a dictionary:
NSDictionary *conds = @{ @"key1": @"value1", @"key2", @"value2" };
NSMutableArray *predicates = [NSMutableArray arrayWithCapacity:conds.allKeys.length];
for (NSString *key in conds.allKeys)
{
[predicates addObject:[NSPredicate predicateWithFormat:@"%K == %@", key, conds[key]]];
}
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
Upvotes: 4
Reputation: 539705
To create a predicate (with a variable number of expressions) dynamically, use NSCompoundPredicate
, e.g.
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: subPredicates)
where subPredicates
is a [NSPredicate]
array, and each subpredicate
is created from the provided arguments in a loop with
NSPredicate(format: "%K == %@", key, value)
Something like this (untested):
func fetchWithPredicate(entityName: String, argumentArray: [NSObject]) -> [NSManagedObject] {
var subPredicates : [NSPredicate] = []
for i in 0.stride(to: argumentArray.count, by: 2) {
let key = argumentArray[i]
let value = argumentArray[i+1]
let subPredicate = NSPredicate(format: "%K == %@", key, value)
subPredicates.append(subPredicate)
}
let fetchRequest = NSFetchRequest(entityName: entityName)
fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: subPredicates)
// ...
}
Upvotes: 16
Reputation: 285069
In your example the %K
and %@
format tokens are replaced only by the first two items of the argument array, the other items are ignored.
You have to provide all format tokens to be replaced in the string for example
NSPredicate(format: "%K == %@ AND %K == %@", argumentArray:["key1", "value1", "key2", "value2"])
Upvotes: 20