Creating NSPredicate from string - iphone

I need to form a predicate from multiple arrays of values. So I thought I can initially form a string with all the values, and then pass that string for usage in a predicate, i.e
NSString* stringForPredicate = [[NSString alloc] init];
if (fromDate != nil) {
stringForPredicate = [stringForPredicate stringByAppendingFormat:#"(Date > %# AND Date < %#)", fromDate, toDate];
}
There are further calculations that I do to form the final predicate string.
Now, I want the predicate to use this string. I thought that something like this would work:
NSPredicate* filterPredicate = [NSPredicate predicateWithFormat:#"%#",stringForPredicate];
But it doesnt and throws the exception:
'Unable to parse the format string "%#"'
Is there a way I can make this work?
thanks,

The stringForPredicate variable actually contains the format_string. So, you need to assign that variable in place of the format_string, and pass the args after that, seperated by commas, like this.
NSSring *stringForPredicate = #"(Date > %# AND Date < %#)";
NSPredicate* filterPredicate = [NSPredicate predicateWithFormat:stringForPredicate, fromDate, toDate];
For compound predicates:
NSMutableArray *subPredicates = [NSMutableArray array];
if (fromDate != nil) {
NSPredicate *from_predicate = [NSPredicate predicateWithFormat:#"Date > %#", fromDate];
[subPredicates addObject:from_predicate];
}
if (toDate != nil) {
NSPredicate *to_predicate = [NSPredicate predicateWithFormat:#"Date < %#", toDate];
[subPredicates addObject:to_predicate];
}
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];

Wont this do it?
NSPredicate* filterPredicate = [NSPredicate predicateWithFormat:stringForPredicate];
or you have to do this
NSPredicate* filterPredicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"%#",stringForPredicate]];
From the reference documents
Format String Summary
It is important to distinguish between
the different types of value in a
format string. Note also that single
or double quoting variables (or
substitution variable strings) will
cause %#, %K, or $variable to be
interpreted as a literal in the format
string and so will prevent any
substitution.
Try this
stringForPredicate = [stringForPredicate stringByAppendingFormat:#"(Date > %#) AND (Date < %#)", fromDate, toDate];

For those using swift:
let predicate = NSPredicate.init("Date > %# AND Date < %#", fromDate, toDate);

Related

ios using filteredArrayUsingPredicate NSPredicate with NSString not working

I'm using to get some of the content of nsmutable array and it work fine if I don't use nsstring to make the query:
NSLog(#"user information %#", [usersInfo filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%K == 'Joe", #"id"]]);
But try to use a nsstring to query for the user it doesn't work:
NSString *user="Joe";
NSLog(#"user information %#", [usersInfo filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%K == user", #"id"]]]);
any of you knows what I'm doing wrong? or what would be the best of doing it using NSString to query for users?
When you write
NSString *user = #"Joe";
... [NSPredicate predicateWithFormat:#"%K == user", #"id"]
you seem to expect that "user" in the predicate is replaced by the contents ("Joe") of the NSString variable, but this is not correct.
You have to give the string
as another argument to the predicate and add the %# format that will be expanded by the string.
NSString *user = #"Joe";
... [NSPredicate predicateWithFormat:#"%K == %#", #"id", user]
Here %K (which is var arg substitution for a key path) will be
substituted by the key "id", and %# (which is
var arg substitution for an object value) will be substituted
by the contents of the user variable.
Using %K expansion instead of
[NSPredicate predicateWithFormat:#"id == %#", user]
has the advantage that it works correctly even if the key is a
reserved word in the predicate format string syntax.
I am unable to gues why you are using "%K == 'Joe"
Anyways, You can use predicate as:
[NSPredicate predicateWithFormat:#"object.property LIKE[c] %#", stringValue];
Or,
[NSPredicate predicateWithFormat:#"object.property==[c] %#", stringValue];
try this:
NSString *user="Joe";
NSLog(#"user information %#", [usersInfo filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF contains [cd] %#", user]]]);
Make your predicate format string before don't try to add property name inside predicate format :
NSString *predicateFormat = [NSString stringWithFormat:#"%# == %%#",#"id"];
NSPredicate *predicate = [NSPredicate predicateWithFormat: predicateFormat, #"Joe"];
NSArray *filteredArray = [mutableArray filteredArrayUsingPredicate:predicate];
Use:
NSLog(#"user information %#", [usersInfo filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"%K == '%#'",#"id",user]]]);
When you use:
NSLog(#"user information %#", [usersInfo filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%K == user", #"id"]]]);"
The user will be a part of the string, it won't replace with the content of the NSString object.

Why is my UISearchController slow?

I have a UISearchResultsController which is filtering my NSFetchedResultsController and putting the filtered data into an array. Currently, I use an NSPredicate to take the search bar content and apply the filter. Here's my predicate:
[filteredArray removeAllObjets];
for(Account *account in unfilteredResults){
NSPredicate *predicate;
if(controller.searchBar.selectedScopeButtonIndex == 0){
predicate = [NSPredicate predicateWithFormat:#"accountFirstName BEGINSWITH[cd] %#", searchString];
}else if(controller.searchBar.selectedScopeButtonIndex == 1){
predicate = [NSPredicate predicateWithFormat:#"accountLastName BEGINSWITH[cd] %#", searchString];
}else if(controller.searchBar.selectedScopeButtonIndex == 2){
predicate = [NSPredicate predicateWithFormat:#"group.groupName CONTAINS[cd] %#", searchString];
}
if([predicate evaluateWithObject:account]){
[self.filteredArray addObject:account];
}
}
I'm trying to filter the accounts based on either first name, last name, or group name. I know that these operations are slow, but what can be done to make them faster?
Edit:
I just noticed that I'm recreating the predicate every iteration, but I still think that there should be a better way. I did see something about doing a binary compare in an Apple video, but I have no idea how to convert a search string into a binary string and less how to get the "next greatest" value.
How do I replace the BEGINSWITH statement with something more efficient?
I'm assuming your data objects are CoreData objects, if so have you marked the properties you are searching on as indexed?
It is too old post, but can help to somebody else. With this code you will create only one instance of NSPredicate.
NSPredicate *predicate;
if(controller,searchBar,.selectedScopeButtonIndex == 0){
predicate = [NSPredicate predicateWithFormat:#"accountFirstName BEGINSWITH[cd] %#", searchString];
}else if(controller,searchBar,.selectedScopeButtonIndex == 1){
predicate = [NSPredicate predicateWithFormat:#"accountLastName BEGINSWITH[cd] %#", searchString];
}else if(controller,searchBar,.selectedScopeButtonIndex == 2){
predicate = [NSPredicate predicateWithFormat:#"group.groupName CONTAINS[cd] %#", searchString];
}
self.filteredArray = [unfilteredResults filteredArrayUsingPredicate:predicate];

Core Data Query Multiple Columns with Single Search String

I have a simple Core Data model with two string attributes (size and category). Given a search string like 'small widget' is it possible to return records that match all the query words to at least one attribute (i.e. all records with 'small' size and 'widget' category)? I currently have:
NSString *search = #"small widget"
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"size contains[cd] %# OR category contains[cd] %#", search, search];
...
This won't return any results (as no category or size equals "small widget"). Any suggestions? Note that the search strings will be user entered from a text field and may come in any order so I can't split up manually.
I haven't tested it but it looks like your want this:
NSString *search = #"small widget";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%# contains[cd] size AND %# contains[cd] category", search, search];
The search string would contain (or not) the size and the category, you should ask if the current size or category is contained on the search string.
You could also split the search string and modify your predicate. You should them to identify the one that performs better
NSString *search = #"small widget";
NSArray *array = [search componentsSeparatedByString:#" "];
NSMutableArray *subPredicates = [NSMutableArray array];
for (NSString *q in array) {
[subPredicates addObject:
[NSPredicate predicateWithFormat:#"size contains[cd] %# OR category contains[cd] %#", q, q]];
}
NSCompoundPredicate *predicate = [[[NSCompoundPredicate alloc] initWithType:NSAndPredicateType
subpredicates:subPredicates] autorelease];
For Swift you can fetch multiple columns by using propertiesToFetch
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "<YOUR ENTITY NAME>")
let predicate = NSPredicate(format: "<YOUR PREDICATE>")
fetchRequest.predicate = predicate
fetchRequest.resultType = .dictionaryResultType
// Here is where you can query multiple columns, you can add as much columns as you want and fetch them as an array of dictionaries
fetchRequest.propertiesToFetch = ["column1", "column2", "column3, "column4"]
let sort = NSSortDescriptor(key: "column1", ascending: false)
fetchRequest.sortDescriptors = [sort]

Help creating a predicate for use with filteredArrayUsingPredicate

I am trying to learn how to use predicates and so am trying to replace the following working code with filteredArrayUsingPredicate...
[filteredLocations removeAllObjects];
for (NSString *location in locations) {
NSRange range = [location rangeOfString:query options:NSCaseInsensitiveSearch];
if (range.length > 0) {
[filteredLocations addObject:location];
}
}
Instead I am trying....
[filteredLocations removeAllObjects];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains %#", searchText];
[filteredLocations addObjectsFromArray: [locations filteredArrayUsingPredicate:predicate]];
I am not getting the same results with the predicate as I am with for loop rangeOfString. With the range of string for example searchText returns an 8 item array while with the same value returns only 2 with the predicate. Another example, hono will find honolulu in the locations array while it will not find anything using the predicate.
As I understand it SELF represents the object object being evaluated ie. the locations array, so I think that is the correct syntax.
Any help would be appreciated
Thanks, John
I thought that in your for loop, you specify an option NSCaseInsensitiveSearch but in the predicate you didn't.
You can try with this one
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(SELF contains[cd] %#)", searchText];
More details can be looked at here
NSPredicate Tutorial

NSPredicate usage

I am having string #"King (+$100)".I want to use NSPredicate to find if string is having (+$[0-9]*).So how to use NSPrdicate
Try this:
// The string to evaluate
NSString *string = #"King (+$100)";
// The regular expression
NSString *regExp = #".*\\(\\+\\$[0-9]*\\).*";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",regExp];
// Test if the object checks the regular expression
BOOL ok = [predicate evaluateWithObject:string];
For all documentation on the NSPredicate see:
NSPredicate Programming Guide