Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Core Data how to properly compare string text using predicates?

This is literally driving me nuts.

I have 2 entities that use NSStrings as unique attribute.

What is the correct way to create a predicate that compares NSStrings?

Currently I have: [NSPredicate predicateWithFormat:@"unique= %@", uniqueValue];

I have a feeling that this compares the pointer addresses, not actual string values, but I cannot confirm that. I need to return yes for an exact string match.

-(BOOL)uniqueEntityExistsWithEnityName:(NSString*)entityName UniqueKey:(NSString*) uniqueKey UniqueValue:(NSString*)uniqueValue SortAttribute:(NSString*)sortDescriptorAttribute ManagedObjectContext:(NSManagedObjectContext*) context;
{
    BOOL returnValue = NO;

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];

//what is the correct predates to compare the text an string core data property against a passed in string?
    request.predicate = [NSPredicate predicateWithFormat:@"unique= %@", uniqueValue];

    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:sortDescriptorAttribute ascending:YES];
    request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];   

    NSError *error = nil;
    NSArray *matches = [context executeFetchRequest:request error:&error];
    if (!matches)
    {
         NSLog(@"Error: no object matches");
    }
    else if([matches count] > 1) {
        NSLog(@"Error: More than one object for unique record");
        returnValue = YES;

    } else if ([matches count] == 0) {
        returnValue = NO;
    } else {
        returnValue = YES;
    }

    return returnValue;
}
like image 779
Alex Stone Avatar asked Mar 22 '12 15:03

Alex Stone


2 Answers

A single equal sign is not even a comparator in terms of coding.

I'm going to assume unique is an NSManagedObject attribute.

[NSPredicate predicateWithFormat:@"unique LIKE %@", uniqueValue];

Note that this is case-sensitive. If you want to make it insensitive, then you can put [c] after the LIKE.

like image 153
Kevin Low Avatar answered Nov 08 '22 20:11

Kevin Low


I don't see a problem with your predicate. A single = is perfect if you want to match exact strings. If you don't need wildcard matching you don't need the slower LIKE. (Predicate Format String Syntax)

However, there is a problem in your code, and it might lead you to assumptions that are not correct. Your if/then/else, or at least the first message is kind of wrong. If you fetch does not return an array it means the fetch failed, it does not mean that the fetch didn't return objects.

It should be more like this:

if (!matches)
{
    NSLog(@"Error: couldn't execute fetch request %@", error);
}
else if([matches count] > 1) {
    NSLog(@"Error: More than one object for unique record");
    returnValue = YES;
} else if ([matches count] == 0) {
    NSLog(@"couldn't match objects");
    returnValue = NO;
} else {
    // [matches count] == 1
    NSLog(@"matched one object");
    returnValue = YES;
}

Oh, and I would change the order of the conditions. In my opinion a structure like (!matches), ([matches count] == 1), ([matches count] == 0), (else) makes more sense and it's easier too read. You put the most important (because it is what you actually want) condition in the last "anonymous" else.

like image 25
Matthias Bauch Avatar answered Nov 08 '22 21:11

Matthias Bauch