5
votes

The question is solved, here is how I fixed it for future reference for noobs like me I needed to remove the white-spaces: ship.countryOfbuild = [[elements objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

And I had to change the predicate like this: NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"(countryOfBuild contains[cd] %@) OR (shipBuilder contains[cd] %@) OR (name contains[cd] %@) OR (owner contains[cd] %@)",searchText, searchText, searchText, searchText];

Original question

I'm using this tutorial to add a search bar to my project. I got the tableview all working, but the search function is crashing the app. The way I search now is:

-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate
                                predicateWithFormat:@"SELF contains[cd] %@",
                                searchText];

searchResults = [searchContent filteredArrayUsingPredicate:resultPredicate];
}

The searchContentis a mutable array read from a .csv-file like this:

- (void)viewDidLoad
{
[super viewDidLoad];
NSString* pathToFile = [[NSBundle mainBundle] pathForResource:@"ships" ofType: @"csv"];

NSString *file = [[NSString alloc] initWithContentsOfFile:pathToFile encoding:  NSUTF8StringEncoding error:NULL];

NSArray *allLines = [file componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];


searchContent           = [[NSMutableArray alloc] init];


for (NSString* line in allLines) {
    NSArray *elements = [line componentsSeparatedByString:@";"];
    
    CargoShips* ship = [[CargoShips alloc]init];
    ship.countryOfbuild =  [elements objectAtIndex:0];
    ship.shipBuilder =     [elements objectAtIndex:1];
    ship.hullHashtag =     [elements objectAtIndex:2];
    ship.name =            [elements objectAtIndex:3];
    ship.owner =           [elements objectAtIndex:4];
    ship.shipOperator =    [elements objectAtIndex:5];
    ship.shipDelivery =    [elements objectAtIndex:6];
    ship.shipFlag =        [elements objectAtIndex:7];
    ship.shipClass =       [elements objectAtIndex:8];
    ship.powerPlant =      [elements objectAtIndex:9];
    ship.HP =              [elements objectAtIndex:10];
    ship.speed =           [elements objectAtIndex:11];
    ship.cargoSystem =     [elements objectAtIndex:12];
    ship.numberOfTanks =   [elements objectAtIndex:13];
    ship.size =            [elements objectAtIndex:14];
    [self.searchContent   addObject:ship];
}

I would like the search to search through all 15 pieces of the object (name, size, shipclass etc)

Currently, this crashes with the error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't use in/contains operator with collection <CargoShips: 0x714e1b0> (not a collection)'

CargoShips is my NSObject class.

How do I fix the NSPredicate to search through an NSMutableArraywith objects without crashing?

Here is the full code if that makes stuff easier http://pastebin.com/sw12GwHK

3

3 Answers

6
votes

You get this error because a ship is not a collection, so you can't use contains -- I think you need to search for a particular field in your ship object, and use LIKE not CONTAINS:

NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF.shipBuilder LIKE[cd] %@",searchText];

With LIKE you can use wild cards in the search. You could also use BEGINSWITH or ENDSWITH to search for the beginning or end of words.

4
votes

Don't use SELF in your predicate, since that will use the actual instance of a CargoShip. In your linked example SELF works good, since it's an NSString.

You can for instance do something like:

@"(countryOfBuild contains[cd] %@) OR (shipBuilder contains[cd] %@)". etc. etc.

3
votes

I use:

NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"self.youProperty contains[c] %@", searchString];
searchArrayObjects = [arrayObjects filteredArrayUsingPredicate:resultPredicate];

Links to documentation