NSPredicate to handle NIL string as ANY character - ios

I have an NSPredicate looks like that:
NSPredicate *predicateSearch;
if ([category_array count]>0 && [location_array count]>0) {
predicateSearch =[NSPredicate predicateWithFormat:#"category_id IN %# AND location_id IN %# AND company_title CONTAINS %#",category_array,location_array,searchStr];
}
else if ([category_array count]>0){
predicateSearch =[NSPredicate predicateWithFormat:#"category_id IN %# AND company_title CONTAINS %#",category_array,searchStr];
}
else if([location_array count]>0){
predicateSearch = [NSPredicate predicateWithFormat:#"location_id IN %# AND company_title CONTAINS %#",location_array,searchStr];
}
[fetchRequest setPredicate:predicateSearch];
Since NSPredicate is not able to handle Nil values I am using this If-Statement to format the Predicate and handle the Nilvalue as 'ANY'.
The issue here is that I want also the searchStr to be handled as 'ANY' if it's Nil.
I tried to set it as empty string in case of Nil but it won't work.
Is there any way to accomplish that without using any If-statements for each case(9 if-statements it's too much)?

Use compound predicates. Example, based on what you posted:
NSPredicate *categoryPredicate = (category_array.count > 0)
? [NSPredicate predicateWithFormat:#"category_id IN %#", category_array]
: [NSPredicate predicateWithValue:YES];
NSPredicate *locationPredicate = (category_array.count > 0)
? [NSPredicate predicateWithFormat:#"location_id IN %#", location_array]
: [NSPredicate predicateWithValue:YES];
NSPredicate *searchPredicate = (searchStr.length > 0)
? [NSPredicate predicateWithFormat:#"company_title CONTAINS %#", searchStr]
: [NSPredicate predicateWithValue:YES];
NSCompoundPredicate *predicate =
[NSCompoundPredicate
andPredicateWithSubpredicates:#[
categoryPredicate,
locationPredicate,
searchPredicate,
]
];

Related

How to concatenate two fields for search with NSPredicate?

For example, I have object like #{#"firstName":#"aaa", #"lastName":#"bbb"}.
Now I'm trying to search with next predicate:
NSPredicate *predicateFirstName = [NSPredicate predicateWithFormat:#"firstName contains [c] %#", searchString];
NSPredicate *predicateLastName = [NSPredicate predicateWithFormat:#"lastName contains [c] %#", searchString];
NSPredicate *orPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[predicateFirstName, predicateLastName]];
searchUsersArray = [usersArray filteredArrayUsingPredicate:orPredicate];
I need a predicate, which will be return for search string #"aa bb" users whose first name ENDED with "aa" and lastName BEGINS with #"bb"
NSPredicate *predicateLastName = [NSPredicate predicateWithFormat:#"(firstName AND lastName contains [c] %#)", searchString]
don't work for me.
First divide the search string in the end-part and the begin-part:
NSArray *parts = [#"aa bb" componentsSeperatedByString:#" "];
Then use BEGINSWITH and ENDSWITH:
[NSPredicate predicateWithFormat:#"(firstName ENDSWITH[c] %#) AND (lastName BEGINSWITH[c] %#", parts[0], parts[1]];
Alternatively you can add a computed property to the entity concatinating the first name and last name and then search in this property.
Try like this hope it help you
NSString *matchString = [NSString stringWithFormat: #"(.*aa|bb.*)",searchText];
NSString *predicateString = #"keyword MATCHES[c] %#";
NSPredicate *predicate =[NSPredicate predicateWithFormat: predicateString, matchString];
Thanks
Use keyword BEGINSWITH instead of contains.
NSPredicate *predicateFirstName = [NSPredicate predicateWithFormat:#"firstName BEGINSWITH [c] %#", searchString];
NSPredicate *predicateLastName = [NSPredicate predicateWithFormat:#"lastName BEGINSWITH [c] %#", searchString];

How to use a compound NSPredicate?

I would like to know how if at all to use a compound NSPredicate?
I have made an attempt as follows however the currentInstall array is exactly the same at the start as it is after the predicate has been applied.
NSArray *currentInstall = [coreDataController filterReadInstalls:selectedInstallID];
NSArray *tempArray = [currentInstalls filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"cHR == 0"]];
currentInstalls = [tempArray copy];
NSPredicate *predicateAreaString = [NSPredicate predicateWithFormat:#"area == %#", [myFilter objectForKey:#"area"]];
NSPredicate *predicateBString = [NSPredicate predicateWithFormat:#"stage == %#", [myFilter objectForKey:#"area2"]];
NSPredicate *predicateCString = [NSPredicate predicateWithFormat:#"partCode == %#", [myFilter objectForKey:#"area3"]];
NSPredicate *predicateDString = [NSPredicate predicateWithFormat:#"doorNo CONTAINS[cd] %#", [myFilter objectForKey:#"door"]];
NSPredicate *predicateEString = [NSPredicate predicateWithFormat:#"doorDesc CONTAINS[cd] %#", [myFilter objectForKey:#"doorDesc"]];
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[predicateAreaString, predicateBString, predicateCString, predicateDString, predicateEString]];
NSMutableArray *filteredArray = [NSMutableArray arrayWithArray:[currentInstalls filteredArrayUsingPredicate:compoundPredicate]];
currentInstalls = [filteredArray mutableCopy];
There doesn't seem to be anything obviously wrong with the way you have implemented NSCompundPredicate. If you are not trying to And or Not predicates then I would say it is something wrong with your predicate formats and how they match the array you are filtering.
I would try to use just 2 of the predicates to create an NSCompundPredicate then get that working or see what is causing your issue. NSHipster also has some good info about NSPredicates.

NSPredicate find an array inside db

I have the DB that contains an
NSString *Number
NSSet *Values
I can easily get all the results based on the string Number with the following:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Number LIKE[c] %#", numberValue];
NSArray *result = [DB MR_findAllWithPredicate:predicate inContext:_context];
If instead of Number I want to pass an Array of values, how can I find in db all the results that contain the given array (NSSet)?
NSPredicate *predicate = [NSPredicate predicateWithFormat: ????
NSArray *result = [DB MR_findAllWithPredicate:predicate inContext:_context];
UPDATE
Based on Igoris answer :
[NSPredicate predicateWithFormat:#“(Values.#count == %d) AND (SUBQUERY(Values, $x, $x IN %#).#count == %d)", allValues.count, allValues, allValues.count];
This seem to work but it doesn t return all the values in result.
Just use IN:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Number IN[c] %#", numberValues];
Where numberValues is NSArray containing numbers you are looking for
UPDATE:
After data structure clarifications I came up with the following predicate to get objects:
[NSPredicate predicateWithFormat:#“(Values.#count == %d) AND (SUBQUERY(Values, $x, $x IN %#).#count == %d)", allValues.count, allValues, allValues.count];
How about ANY and NONE?
[NSPredicate predicateWithFormat:#"ANY number == %#", numberValues];

I can't use two operator in predicatewithformat in same time

NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES[cd] %# AND (NOT (SELF MATCHES[cd] %#))", [NSString stringWithFormat: #".*\\b%#.*", string],[NSString stringWithFormat: #".*\\[\\b%#.*", string]];
What is wrong in my code?
try with subquery function it's helpful you
[NSPredicate predicateWithFormat#"(add == %#) AND (SUBQUERY(subs, $x, $x.numbervalue == %# or $x.numbervalue == %#).#count > 0)", #"add",number1, number2];
Another:
AND & OR can be used in predicate format strings to create compound predicates. However, the same can be accomplished using an NSCompoundPredicate.
For example, the following predicates are equivalent:
[NSCompoundPredicate andPredicateWithSubpredicates:#[[NSPredicate predicateWithFormat:#"age > 25"], [NSPredicate predicateWithFormat:#"firstName = %#", #"Raja"]]];
[NSPredicate predicateWithFormat:#"(age > 25) AND (firstName = %#)", #"Raja"];
Source: Mattt Thompson

Trying to make a compond predicate. Not working.

I am trying to make a compound predicate for my core data search. So when the user enters text in the search bar, it will display results for anything that has that text in either the name, optionOne or optionTwo attributes.
I tried this:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
if (self.sBar.text !=nil) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(name contains[cd] %#) || (optionOne contains[cd] %#) || (optionTwo contains[cd] %#)", self.sBar.text];
[fetchedResultsController.fetchRequest setPredicate:predicate];
}
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
// Handle error
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
[self.myTable reloadData];
[sBar resignFirstResponder];
}
But it just crashes without a descriptive reason. So I think I need to take these three predicates and somehow combine them:
NSPredicate *namePredicate = [NSPredicate predicateWithFormat:#"name contains[cd] %#", self.sBar.text];
NSPredicate *optionOnePredicate = [NSPredicate predicateWithFormat:#"optionOne contains[cd] %#", self.sBar.text];
NSPredicate *optionTwoPredicate = [NSPredicate predicateWithFormat:#"optionTwo contains[cd] %#", self.sBar.text];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(name contains[cd] %#) || (optionOne contains[cd] %#) || (optionTwo contains[cd] %#)", self.sBar.text];
Since you have 3 %# tokens in your string, you need to have 3 self.sBar.text expressions at the end.
Alternatively, you could do something like this:
NSPredicate *template = [NSPredicate predicateWithFormat:#"name contains[cd] $SEARCH OR optionOne contains[cd] $SEARCH OR optionTwo contains[cd] $SEARCH"];
NSDictionary *replace = [NSDictionary dictionaryWithObject:self.sBar.text forKey:#"SEARCH"];
NSPredicate *predicate = [template predicateWithSubstitutionVariables:replace];
This is handier if you're building this predicate a lot, because you can store the "template" predicate in an ivar. Parsing a predicate is not the snappiest of things, and using the template version means you'll only have to parse it once (instead of every time the search bar's text changes).

Resources