Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using NSPredicate contains to find characters inside a coredata entity's field

I'm trying to find all customers that contain a certain sequence of letters. I want identical functionality to NSString's rangeofString except case insensative. Heres my method:

-(NSArray *) db_search: (NSString *) table where: (NSString*) fieldKey contains: (NSString*) value withSortField: (NSString *) sortField{
    NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
    NSEntityDescription *entity = [NSEntityDescription entityForName:table inManagedObjectContext:context];
    if (fieldKey != nil){
        NSPredicate *predicate = [NSPredicate
                                  predicateWithFormat:@"(%@ contains[c] %@)",
                                  fieldKey,value];
        [request setPredicate:predicate];
    }
    [request setEntity:entity];

    if (sortField != nil){
        NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:[self extractSortField:sortField] ascending:[self isAscending:sortField]] autorelease];
        NSArray *sortDescriptors = [[[NSArray alloc] initWithObjects:sortDescriptor, nil] autorelease];
        [request setSortDescriptors:sortDescriptors];
    }

    NSError *error;
    return [context executeFetchRequest:request error:&error];
}

I'm calling it with these values:

NSArray * results = [self db_search:@"Customer" where:@"fullname" contains:@"matt" withSortField:nil];

Instead of getting all Matts, Matthews, etc, it freezes when I try to print out the results. I debugged it and we don't even get an empty NSArray back. I print the NSArray to console and I don't get 0 elements.. I just get nothing.

I've tried doing a dump of the DB to console and it contains all the right things in it. HELP!!!

=UPDATE======================================================

I am using %K and I'm getting a wierd runtime error:

if (searchResults1 != nil){
    NSLog(@"%Matches: %i", [searchResults1 count]);
}else {
    NSLog(@"Was NULL");
}

Its on the NSLog(@"%Matches: line. Its a BAD EXC error. So searchResults1 is not nill but it crashes when I try to read the count? When I debug, searchResults1 is indeed an NSArray but it doesn't seem to have anything inside it.

like image 813
Mike S Avatar asked Mar 17 '11 07:03

Mike S


2 Answers

It looks like your problem is your predicate:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(%@ contains[c] %@)", fieldKey,value];

When you pass in fieldKey = @"fullname" and value = @"matt", this predicate is going to be equivalent to:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"('fullname' contains[c] 'matt')"];

Do you see the problem? It's treating "fullname" as a raw string, and not as the name of a field. This is because you're using the %@ modifier in the format string. When NSPredicate comes across those, it says "aha! the value that gets substituted in here will be a constant". What you really want it to do is say "aha! the value that gets substituted in here will be an identifier".

So instead of using %@, use %K. This is a special modifier just for predicates, and it means to substitute in the string as an identifier (really as a "keypath"), which means it will make your predicate be:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(fullname contains[c] 'matt')"];

Which is what you're looking for.

like image 112
Dave DeLong Avatar answered Oct 17 '22 01:10

Dave DeLong


I can tell from the way you named your variables and parameters that you are thinking in SQL terms. Core Data is not SQL. Entities are not tables. Objects are not rows. Columns are not attributes. Core Data is an object graph management system that may or may not persist the object graph and may or may not use SQL far behind the scenes to do so. Trying to think of Core Data in SQL terms will cause you to completely misunderstand Core Data and result in much grief and wasted time.

In this block:

if (searchResults1 != nil){
    NSLog(@"%Matches: %i", [searchResults1 count]);
}else {
    NSLog(@"Was NULL");
}

... you have two problems here. Firstly, searchResults1 will never be nil. Regardless of whether the fetch finds any objects, it will return an array object. Instead, you should check the count of the array. Secondly, the %Matches is a typo. The % is a formatting control character and will cause the complier to look for a control code e.g. %@ immediately afterward. Try this instead:

if ([searchResults1 count]>0){
    NSLog(@"Matches: %i", [searchResults1 count]);
}else {
    NSLog(@"No managed objects found");
}
like image 44
TechZen Avatar answered Oct 17 '22 00:10

TechZen