NSPredicate unable to parse format string - ios

I can't see any problem with these line of code. Why can't it parse?
[NSPredicate predicateWithFormat:#"(username CONTAINS[cd] %1$#) || "
"(userId CONTAINS[cd] %1$#) || "
"(firstname CONTAINS[cd] %1$#) || "
"(lastname CONTAINS[cd] %1$#)", searchString]"
The Log doesn't help either.
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'Unable to parse the format
string "(username CONTAINS[cd] %1$#) || (userId CONTAINS[cd] %1$#) ||
(firstname CONTAINS[cd] %1$#) || (lastname CONTAINS[cd] %1$#)"'
Edit 1:
Okay, it seems like predicateWithFormat doesn't understand "%1$#". I switch it to
[... predicateWithFormat:[NSString stringWithFormat:...]] // (same format as above)
It passed the line. But, the next problem is:
self.filteredUserList = [self.userList filteredArrayUsingPredicate:predicate];
Terminating app due to uncaught exception 'NSUnknownKeyException',
reason: '[ valueForUndefinedKey:]: the entity User is
not key value coding-compliant for the key "a".'
"a" is the keyword I entered in the searchTextBox. WUT?
I printed out the predicate in the debug console, looks nothing wrong:
username CONTAINS[cd] a OR userId CONTAINS[cd] a OR firstname CONTAINS[cd] a OR lastname CONTAINS[cd] a
Edit 2:
Okay, problem solved with this super ugly code:
[NSPredicate predicateWithFormat:#"(username CONTAINS[cd] %#) || "
"(userId CONTAINS[cd] %#) || "
"(firstname CONTAINS[cd] %#) || "
"(lastname CONTAINS[cd] %#)", searchString, searchString, searchString, searchString];
What if I want to expand the search field in the future? I've got to add more parameters? more ", searchString, searchString, searchString"?
SOLVED
Thanks to Ewan and Bannings, giving 2 options to my question. I tested both of them, and they worked liek a charm. Can someone explain the different between those two, and in which case should I use which option?
** NOTE **
Bannings' answer is alright, until my search string contains a single quote ', then the app crash. So I think use Ewan's one is better.

You can do this:
[[NSPredicate predicateWithFormat:#"(username CONTAINS[cd] $str) || ..."] predicateWithSubstitutionVariables:#{#"str": searchString}];

Try change %1$# to '%1$#':
NSString *formatString = [NSString stringWithFormat:#"(username CONTAINS[cd] '%1$#') || (userId CONTAINS[cd] '%1$#') || (firstname CONTAINS[cd] '%1$#') || (lastname CONTAINS[cd] '%1$#')", searchString];
NSPredicate *predicate = [NSPredicate predicateWithFormat:formatString];

You need to add the string for each variable, if you use 5 %# you need to apply either the same searchString value or another value filling for that %#
[NSPredicate predicateWithFormat:#"(username CONTAINS[cd] %1$#) ||
(userId CONTAINS[cd] %1$#) || (firstname CONTAINS[cd] %1$#) ||
(lastname CONTAINS[cd] %1$#)", searchString1,searchString2,searchString3,searchString4]

Related

Core data Fetch request error for predicate

Need
I have to find the record with rec_name is "Apple 256GB Macbook" & isActive == true.
Fetch Request
fetchRequest.predicate = NSPredicate(format: "rec_name LIKE[cd] *%#* AND rec_name LIKE[cd] *%#* AND isActive = %#","apple","macbook",true)
Error
Unable to parse the format string "rec_name LIKE[cd] *%#* AND rec_name LIKE[cd] *%#* AND isActive = %#"
Thank you,
The problem is because of *%#* here %# between the * is not replaced by a string argument so NSPredicate is not able to make your query LIKE *apple* and LIKE *macbook* what you need to do is make a search string with wildcards and with Like simply use %#, also as #Vadian suggested use number instead of Bool.
let searchkeyword1 = "apple"
let searchkeyword2 = "macbook"
//Make search string wildcards charaters
let searchString1 = "*\(searchkeyword1)*"
let searchString2 = "*\(searchkeyword2)*"
fetchRequest.predicate = NSPredicate(format: "rec_name LIKE[cd] %# AND rec_name LIKE[cd] %# AND isActive = %#", searchString1,searchString2, true as NSNumber)
Also batter option here is you can use CONTAINS and no need to use of wildcards.
fetchRequest.predicate = NSPredicate(format: "rec_name CONTAINS[cd] %# AND rec_name CONTAINS[cd] %# AND isActive = %#", "apple","macbook", true as NSNumber)
You can do one more thing if you want to find all record start with apple and end with macbook then you can simply use BEGINSWITH and ENDSWITH
fetchRequest.predicate = NSPredicate(format: "rec_name BEGINSWITH[cd] %# AND rec_name ENDSWITH[cd] %# AND isActive = %#", "apple","macbook", true as NSNumber)
Try this
fetchRequest.predicate = NSPredicate(format: "rec_name LIKE[cd] %# AND rec_name LIKE[cd] %# AND isActive = %#","apple","macbook",NSNumber(booleanLiteral: true))
You need to set a predicate query like following:
fetchRequest.predicate = NSPredicate(format: "rec_name == %# AND isActive == %#" , "Apple 256GB Macbook", NSNumber(booleanLiteral: true))
I don't think we need to use Like if you are looking for perfect match.
Try this
NSPredicate(format: "rec_name == %# AND rec_name == %# AND isActive = %d","apple","macbook",true)

NSPredicate execureFetchRequest not working - possibly due to spaces in string

I am trying to search in CoreData for an object that matches both a recordId and a string name, but it doesn't always find the object.
For example, I an searching for an object with id 1000 and name "The Brown Family" (note the 2 spaces between "The" and "Brown").
If I use:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(recordId == %#") AND (name like[cd] %#)", recordId, name];
with recordId=1000 and name="The Brown Family", the fetch request returns nil.
If I use:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(recordId == %#"), recordId];
with recordId=1000, it finds the object. If I print the object's name property, I get "The Brown Family".
So the object is there with the correct id and name, but my fetchRequest fails.
What am I doing wrong?
You might need to enclose the value in single quotes...
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(recordId == %#) AND (name like[cd] '%#')", recordId, name];
Sorry but I realise what the problem is now! The name I was searching for had a trailing space after it. So I was looking for say "Toby " whereas "Toby" was stored in Coredata.
Sorry for wasting everyone's time.

How to concatenate two column values and compare in ios

In my entity Contact, I have two columns named firstName & lastName. I want to search for a name entered by user in my DB.
For Eg: If user enters only 'William' I can search either its present in first name or last name and show the result.
If the user enters 'William Smith', then I want to get both first name and last name from DB and compares it with search text.
For this i want to use NSPredicate that compares 3 condition:
firstName contains the search text OR
lastName contains the search text OR
firstName+lastName contains the search text.
I used the following predicate for that:
NSString *strSearchType = #"(%# CONTAINS[cd] '%#' OR %# CONTAINS[cd] '%#' OR (%# || %# CONTAINS[cd] '%#')";
I know "||" is the concatenate operator.
But it gives me the following exception:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "(firstName CONTAINS[cd] 'rus' OR lastName CONTAINS[cd] 'rus' OR ((firstName || lastName) CONTAINS[cd] 'rus'))"'
Am i doing anything wrong ?
You can try following :
firstName contains the search text OR
lastName contains the search text OR
(search text contains the firstName AND search text contains the lastName).
NSString* stringA=nil; NSString* stringB=nil;
// this would give array of string separated by space
NSArray *searchStrArray = [searchString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" "]];
if (searchStrArray.count>0) {
stringA=[searchStrArray objectAtIndex:0];
}
if (searchStrArray.count>1) {
stringB=[searchStrArray objectAtIndex:1];
}
NSPredicate* predicateA= [NSPredicate predicateWithFormat:#“firstName CONTAINS[c] %# OR lastName CONTAINS[c] %#",stringA , stringA];
NSPredicate* resultPredicate=predicateA;
if(stringB){
NSPredicate* predicateB= [NSPredicate predicateWithFormat:#“firstName CONTAINS[c] %# OR lastName CONTAINS[c] %#",stringB , stringB];
resultPredicate=[NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:resultPredicate,predicateB, nil]];
}

How to apply a boolean operation in an NSPredicate?

I have the following Search NSPredicate
NSPredicate *searchPredicateTextComponent = [NSPredicate predicateWithFormat:#"(SUBQUERY(entities, $x , ((ANY $x.objects.type LIKE 'text') AND ((ANY $x.objects.desc CONTAINS[c] %#) OR (ANY $x.objects.desc BEGINSWITH[c] %#)))).#count != 0)", [NSString stringWithFormat:#" %#",subString],subString ];
Now I need to block the objects that don't have a boolean combination to be true which is:
i.e. if P = $x.isAllowed, S = $x.shouldByPass then boolean operation P'S == TRUE must be added to the NSPredicate.
Is this possible or feasible?

NSPredicate format specifiers issue

I use this predicate:
NSPredicate *offencePredicate =
[NSPredicate predicateWithFormat:#"(%# == %#) AND (%# == %d)", kTeamID, self.selectedTeam.teamID, kPlayerZoneID, ZoneIdTypeOffence];
but the predicate is:
"teamID" == 10 AND "playerZoneID" == 3
instead of:
teamID == 10 AND playerZoneID == 3
How can I trim this "" when I use format specifiers for predicating. And the next question is: is this the right solution using form specifiers in predicate. Because I have some API keys that are correspond to my core data entries attributes. So it is ok to use constant string that will allow quite faster changes if I need to change some of these keys, but is it ok to use this constant for predication?
You need to use %K for the keys.
It would look like this:
[NSPredicate predicateWithFormat:#"(%K == %#) AND (%K == %d)", kTeamID, self.selectedTeam.teamID, kPlayerZoneID, ZoneIdTypeOffence];
Use %K.
See this example from the documentation:
NSString *attributeName = #"firstName";
NSString *attributeValue = #"Adam";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#",
attributeName, attributeValue];
Result:
firstName like "Adam"

Resources