In my iOS application I have a really simple predicate for my fetch controller.
NSString *format = [NSString stringWithFormat:@"name like[c] '%@'", nameVar];
NSPredicate *predicate = [NSPredicate predicateWithFormat:format];
[fetchController setPredicate:predicate];
It performs basic case-insensitive name lookup. Now I'd like to change it so that I could put a number of words in search box (nameVar has the value from search box) separated by spaces and have the predicate filter the results matching all those keywords.
So if I have two names: "John Smith" and "Mary Smith" and I search for: "Smith M" I would like to have only one result but a search like that: "Sm th ith" should return both values.
Does anyone have an idea how should this be implemented?
NSPredicate is a Foundation class that specifies how data should be fetched or filtered. Its query language, which is like a cross between a SQL WHERE clause and a regular expression, provides an expressive, natural language interface to define logical conditions on which a collection is searched. It’s easier to show NSPredicate in...
%@ is a var arg substitution for an object value—often a string, number, or date. %K is a var arg substitution for a key path. $VARIABLE_NAME is a value that can be substituted with NSPredicate -predicateWithSubstitutionVariables:. =, ==: The left-hand expression is equal to the right-hand expression.
NSDictionary can use predicates by filtering its keys or values (both NSArray objects). NSOrderedSet can either create new ordered sets from a filtered NSArray or NSSet, or alternatively, NSMutableSet can simply removeObjectsInArray:, passing objects filtered with the negated predicate.
Basically, you go to the link, type in your word, and poof – multisearch happens. You can bookmark that link and reload as needed whenever you want to search for a word.
edit back on a regular computer...
So there are a couple things to be aware of:
NSExpression
and NSPredicate
(specifically NSComparisonPredicate
and NSCompoundPredicate
) objects. Your string will be placed into an NSExpression
of type NSConstantValueExpressionType
, meaning that it's already going to be interpreted as a regular string. Placing the single quotes in the format string will, in fact, make your predicate non-functional.nameVar
). In that case, we'll break the nameVar
up into its constituent words, and create a comparison for each word. Once we've done that, we AND
them together to create a single overarching predicate. The code below does exactly that.original answer
You can do this by building your own NSCompoundPredicate
:
NSString *nameVar = ...; //ex: smith m
NSArray *names = ...; //ex: John Smith, Mary Smith
NSArray *terms = [nameVar componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSMutableArray *subpredicates = [NSMutableArray array];
for(NSString *term in terms) {
if([term length] == 0) { continue; }
NSPredicate *p = [NSPredicate predicateWithFormat:@"name contains[cd] %@", term];
[subpredicates addObject:p];
}
NSPredicate *filter = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
[fetchController setPredicate:filter];
Warning: typed in a browser on my iPhone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With