+[NSPredicate predicateWithFormat] substitute reserved words - nspredicate

Is it possible to substitute reserved words, specifically OR and AND, into a predicateFormat?
I tried:
NSString *andOr = (isAnd ? #"AND" : #"OR"); // isAnd is a BOOL variable
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"firstName == %# %K lastName == %#",
user.firstName, andOr, user.lastName];
But I got:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'Unable to parse the format string "firstName == %# %K lastName == %#"
I tried %s (and also %S) instead of %K but got the same exception.
My working solution for now is to create the predicateFormat separately.
NSString *predicateFormat = [NSString stringWithFormat:
#"firstName == %%# %# lastName == %%#", andOr];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateFormat,
user.firstName, user.lastName];
But, I was wondering if this could be done without creating predicateFormat separately.

Yep, it can:
NSPredicate *firstName = [NSPredicate predicateWithFormat:#"firstName == %#", [user firstName]];
NSPredicate *lastName = [NSPredicate predicateWithFormat:#"lastName == %#", [user lastName]];
NSArray *subpredicates = [NSArray arrayWithObjects:firstName, lastName, nil];
NSPredicate *predicate = nil;
if (isAnd) {
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
} else {
predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
}

Using search bar text i am filtering the data.
Below code is simple and no need of any explanation
NSString *predFormat=[NSString stringWithFormat:#"FirstName CONTAINS[c] '%#' OR LastName CONTAINS[c] '%#' OR Phone CONTAINS[c] '%#'",searchValue,searchValue,searchValue]; //LIKE
NSPredicate *predicate = [NSPredicate predicateWithFormat:predFormat];
NSArray *tempData = [array filteredArrayUsingPredicate:predicate];
Hope this will work for you..
Happy coding....

Related

Predicate in a Core Data fetch doesn't return the same results as the same predicate on a array

In the following example, why don't the two properties arrays have the same elements? The first array is empty, and the second array contains 1 element, yet they use the same predicate...
NSError *error;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"publication.store.storageMode != 0 && publication.store.complete == NO && publication.download == NIL"];
NSFetchRequest *request1 = [NSFetchRequest fetchRequestWithEntityName:#"Property"];
request1.predicate = predicate;
NSArray *properties1 = [self executeFetchRequest:request1 error:&error];
NSFetchRequest *request2 = [NSFetchRequest fetchRequestWithEntityName:#"Property"];
NSArray *allProperties = [self executeFetchRequest:request2 error:&error];
NSArray *properties2 = [allProperties filteredArrayUsingPredicate:predicate];
properties1 has 0 element.
allProperties has 12 elements.
properties2 has 1 element.
I don't understand why the first request doesn't return the one element that I get in the second method. Shouldn't they be equivalent?
This is probably not to be intended as an answer, I didn't know how to write suych long text within a comment. I am not quite sure you cannot fetch with a BOOL directly in your CoreData predicate.
So I would try, for test purpose, to use two different predicates:
NSPredicate *predicateArray = [NSPredicate predicateWithFormat:#"publication.store.storageMode != 0 && publication.store.complete == NO && publication.download == NIL"];
NSPredicate *predicateCoreData = [NSPredicate predicateWithFormat:#"publication.store.storageMode != 0 && publication.store.complete == %# && publication.download == NIL",[NSNumber numberWithBool:myBool]];
Also, I would replace NIL with nil.

Core data predicates with key-paths

So i'm trying to work out how to use these predicates, i've read the Apple doc and am trying to use it (https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pUsing.html) and i have the predicate set up, but it keep getting Thread 1: EXC_BAD_ACCESS (code =) etc.etc.
NSError *error;
NSLog(#"1");
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Fruit" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSLog(#"2");
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"Source.sourceName contains[cd] %#", "Apple Tree"];
[fetchRequest setPredicate:predicate];
NSLog(#"3");
NSArray *fetchResult = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"4");
testLbl.text = [fetchResult objectAtIndex:0];
Thats the code i'm using, as for the Core Data we have...
Entities Fruit & Source
Attributes fruitName & sourceName
Relationship (one to one) fruitSource<--------->sourceFruit
What i want to do is pull out any fruit that comes from an Apple Tree... >.<
There are two different problems:
To get from Fruit to the related Source you have to use the relationship: #"fruitSource.sourceName contains ..." instead of #"Source.sourceName contains ...".
(This is probably causing the exception.) The %# format requires an Objective-C object as argument, not a C string: #"Apple Tree" instead of "Apple Tree".
So the predicate should look like this:
[NSPredicate predicateWithFormat:#"fruitSource.sourceName CONTAINS[cd] %#", #"Apple Tree"]

Xcode: Using a complex predicate to filter a core data set

EDIT: I'm adding a new rough table model for comment. Is this what you had in mind?
I'm still trying to work out a search filter for a core data set. I got stuck here, so I'm approaching the problem differently.
First, what I'm trying to do is the following:
Iterate through all objects (NSManageObject *object in tableViewModel.items)
Extract all the subentity objects for each 'object' and validate against search term.
If the search term does exist in the subentity, then add 'object' to 'autoSearchResults' (if it doesn't already exist there)
My code is as follows:
NSLog(#"%s", __FUNCTION__);
NSMutableArray *startArray = [NSMutableArray array];
NSMutableArray *filteredArray = [NSMutableArray array];
for (NSManagedObject *object in tableViewModel.items)
{
NSLog(#"1 ");
NSSet *set1 = [object valueForKeyPath:#"people.name"];
NSString *str1 = [[set1 allObjects] componentsJoinedByString:#", "];
peopleSet = str1;
NSLog (#"peopleSet is %# ", peopleSet);
NSLog(#"2 ");
NSSet *set2 = [object valueForKeyPath:#"place.name"];
NSString *str2 = [[set2 allObjects] componentsJoinedByString:#", "];
placeSet = str2;
NSLog(#"3 ");
NSSet *set3 = [object valueForKeyPath:#"keyword.name"];
NSString *str3 = [[set3 allObjects] componentsJoinedByString:#", "];
keywordSet = str3;
NSLog(#"4 ");
NSSet *set4 = [object valueForKeyPath:#"type.name"];
NSString *str4 = [[set4 allObjects] componentsJoinedByString:#", "];
typeSet = str4;
NSLog(#"5 ");
NSSet *set5 = [object valueForKeyPath:#"symbol.name"];
NSString *str5 = [[set5 allObjects] componentsJoinedByString:#", "];
symbolSet = str5;
NSLog(#"6 ");
NSLog (#"searchText is: %# ", searchText);
myPredicate = [NSPredicate predicateWithFormat:#"(peopleSet contains[cd] %#) || (placeSet contains[cd] %#) || (keywordSet contains[cd] %#) || (typeSet contains[cd] %#) || (symbolSet contains[cd] %#)", searchText, searchText, searchText, searchText, searchText ];
NSLog(#"7 ");
if (myPredicate) {
[startArray addObject:object];
NSLog (#"startArray.count is %i ", startArray.count);
}
NSLog(#"8 ");
NSLog (#"startArray.count is %i ", startArray.count);
/*
if (startArray.count == 0)
{
NSLog(#"0");
} else {
NSLog(#"9 ");
[filteredArray addObject: startArray];
NSLog(#"10 ");
[startArray removeAllObjects];
NSLog(#"11 ");
}
*/
}
//autoSearchResults = filteredArray;
return autoSearchResults;
}
In my testing, I have 3 objects, one with the person.name "me", one with "you", and one with "Mother". All the other fields are blank in all objects.
Right now, I'm stopping to see how many objects are selected for each search. Essentially, the searchText is found but ignored. That is, the routine sees that the searchText contains "me" for example, but still adds an Object where the actual text is "You".
I would appreciate any help.. If it would help to reduce this example, please let me know..
The most egregiously wrong thing about this code is that you're not actually using the predicate you create. In order to test an object against a predicate, call evaluateWithObject: on the predicate, passing in the object to test.
But that still won't work, because it doesn't know what "peopleSet" and all those other strings are: you can't use a local variable as if it were a keypath.
Finally, this structure doesn't really take advantage of the power of predicates; you're using a predicate like a regex. To actually filter an object collection, use a method such as filteredSetUsingPredicate: on the collection itself instead of testing every object.
Of course, this will require you to create a transient property on your managed object model to store the concatenated list of names, but if you do that correctly, you'll see a performance boost when doing this kind of filtering.

How to filter nsdictionary?

I want to search data from nsdictionary based on different criteria.Say I have 4 keys and user can search based on any number of keys ex:4,3 etc..Ex:I have dictionary containing keys(First Name,Last Name,Address,Phone Number).Now user can search based on any key say First Name and Last Name, or only First Name.I am using NSPredicate to search.My problem is how to create dynamic nspredicate?If I provide empty string in
[NSPredicate predicateWithFormat:#"FirstName CONTAINS[cd] %# AND LastNAme CONTAINS[cd] %# AND Address CONTAINS[cd] %# AND PhoneNumber CONTAINS[cd] %#",firstname,lastname,addr,phone]
It does not give any result.How can I achieve this?or I have to create multiple nspredicate based on fields user has provide?
Thanks in advance!
You can build the predicate programmatically:
NSArray *keysToSearch = [NSArray arrayWithObjects:#"FirstName", #"LastName", #"Address", nil];
NSString *searchString = #"Bob";
NSMutableArray *subPredicates = [NSMutableArray array];
for (NSString *key in keysToSearch) {
NSPredicate *p = [NSPredicate predicateWithFormat:#"%K contains[cd] %#", key, searchString];
[subPredicates addObject:];
}
NSPredicate *filter = [NSCompoundPredicate andPredicateWithSubPredicates:subPredicates];
Then use filter to filter your dictionaries.

Creating predicate with pre-built string

Is there a way to create an nspredicate directly from a pre-formatted string without calling predicateWithFormat? The final string would look something like:
(inpatient=1) AND (dischargedate!=<null>) AND ((attending=SMITH) OR (admitting=SMITH) OR (consulting contains[cd] SMITH) OR (attending=JONES) OR (admitting=JONES) OR (consulting contains[cd] JONES))
NSMutableString *preds = [[NSMutableString alloc] initWithString:#""];
NSArray *provs = [self.providerCode componentsSeparatedByString:#"|"];
for (NSString *prov in provs) {
[preds appendFormat:#" (attending=%#) OR (admitting=%#) OR (consulting contains[cd] %#) ", prov, prov, prov];
}
NSString *final = [NSString stringWithFormat:#"(inpatient=%#) AND (dischargedate!=%#) AND (%#)", [NSNumber numberWithBool: self.inpatients], [NSNull null], preds];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:final]];
Yes you can, but you need to modify the format string slightly.
Instead of doing:
[preds appendFormat:#" (attending = %#)", prov];
You'd need to do:
[preds appendFormat:#" (attending = '%#')", prov];
Note the use of single-quotes around the %# modifier. That's how the predicate knows it's a constant value.
However, even if you go this route, you're still stuck using predicateWithFormat:, which you appear to want to avoid. You'll also likely have issues with how you're using NSNull in the format string.
I would recommend doing something more like this:
NSArray *provs = [self.providerCode componentsSeparatedByString:#"|"];
NSMutableArray *providerPredicates = [NSMutableArray array];
NSPredicate *template = [NSPredicate predicateWithFormat:#"attending = $prov OR admitting = $prov OR consulting CONTAINS[cd] $prov"];
for (NSString *prov in provs) {
NSDictionary *substitutions = [NSDictionary dictionaryWithObject:prov forKey:#"prov"];
NSPredicate *p = [template predicateWithSubstitutionVariables:substitutions];
[providerPredicates addObject:p];
}
NSPredicate *final = [NSPredicate predicateWithFormat:#"inpatient = 1 AND dischargedate != nil"];
if ([providerPredicates count] > 0) {
NSPredicate *providers = nil;
if ([providerPredicates count] > 1) {
providers = [NSCompoundPredicate orPredicateWithSubpredicates:providerPredicates];
} else {
providers = [providerPredicates objectAtIndex:0];
}
final = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:final, providers, nil]];
}
This is using a couple different neat things:
Predicate variables. You parse the format string #"attending = $prov OR admitting = $prov OR consulting CONTAINS[cd] $prov" once, and then simply substitute in new values for $prov each time you have a different provider
Constructing compound predicates. You use some class methods on NSCompoundPredicate to turn multiple predicates into a single, grouped OR or AND predicate.

Resources