1

I have a Car class with instance variables such as "color" and "make". I need a NSPredicate that allows me to search for either color or make or both.

NSPredicate*predicate=[NSPredicate predicateWithFormat:@"(color contains[c] %@) AND (make contains[c] %@)", chosenColor,chosenMake];

This predicate requires that there is BOTH a color and a make. If the user only gives a color, no results will be returned because the make then will be "nil". No cars has nil for any instance variables.

Also, the search will be for many variables, not only color and make, so an if/case situation is not wanted. Is there any options that gives my the possibility to search for "AND if NOT nil". I will appreciate any help.

Tom Tallak Solbu
  • 559
  • 6
  • 20

2 Answers2

3

You can build your predicate format dynamically to test only non-nil attributes. More on that here. Also consider making your search diacritic-insensitive (adding a 'd' to your CONTAINS statement). Take "Škoda" for example. You want people to find it with "skoda" as well.

Léo Natan
  • 56,823
  • 9
  • 150
  • 195
  • Thank you for your reply. The problem using OR, is that a search for "yellow ford" will give all yellow cars, and all fords. I want the searchstring "yellow ford" to result in only fords that are yellow. – Tom Tallak Solbu Oct 11 '12 at 18:20
  • 1
    Then indeed, you should your predicate dynamically. Please check the link I posted. That way, if the user only looks for "yellow", he will find all yellow vehicles, or if he looks for "ford", he will find all Ford vehicles, but if he searches for "yellow ford", he will find only yellow Ford vehicles. – Léo Natan Oct 11 '12 at 19:13
  • Thank you very much. I am beginning to get an idea of this now. – Tom Tallak Solbu Oct 12 '12 at 07:39
2

This is pretty easy with the NSCompoundPredicate API:

NSString *chosenColor = ...;
NSString *chosenMake = ...;

NSMutableArray *subpredicates = [NSMutableArray array];

if (chosenColor != nil) {
  NSPredicate *p = [NSPredicate predicateWithFormat:@"color contains[cd] %@", chosenColor];
  [subpredicates addObject:p];
}

if (chosenMake != nil) {
  NSPredicate *p = [NSPredicate predicateWithFormat:@"make contains[cd] %@", chosenMake];
  [subpredicates addObject:p];
}

NSPredicate *final = nil;
if ([subpredicates count] > 0) {
  final = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
}
Daniel
  • 23,129
  • 12
  • 109
  • 154
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • Thanks. This works well for few istances. If I have "type", "country" and "weight" in addition, where several of these could be nil, there will be a lot of ifs. But if that is the only solution, I will have to go for that. – Tom Tallak Solbu Oct 12 '12 at 06:17
  • @TomTallakSolbu you could have it be more dynamic by having things in a dictionary, etc etc. But this is the *pattern* you'll need to follow. – Dave DeLong Oct 12 '12 at 06:42