7
votes

I have an array of instances of a class called Contact, which has, among others, the following properties:

NSArray *mailAddressList // Array of NSString
NSArray *websiteList // Array of NSString
NSArray *tags // Array of instances of Tag class

The class tag has the following properties:

NSString *name;
UIColor *color;

I want to use NSPredicate to search a string in any property of each Contact. This is the code I have:

if([scope isEqualToString:SCOPE_MAIL] || [scope isEqualToString:SCOPE_WEBSITE])
{
    // Search through an array
    predicate = [NSPredicate predicateWithFormat:@"ANY SELF.%@ contains[c] %@", scope, textSearch];
}
else if([scope isEqualToString:SCOPE_TAG])
{
    // Search another object's property
    predicate = [NSPredicate predicateWithFormat:@"SELF.%@.name contains[c] %@", scope, textSearch];
}
else
{
    // The rest of the properties are instances of NSString
    predicate = [NSPredicate predicateWithFormat:@"SELF.%@ contains[c] %@", scope, textSearch];
}

Everything works fine except for SCOPE_TAG, it doesn't return any values. I don't think I'm using the predicate correctly.

NOTE: I'm new with NSPredicate so I would like to hear some insights if what I'm doing is not ok

1
Not 100% sure whether this is what's responsible for your problem, but you should be using the %K format specifier for keypaths instead of %@. So for example the format string for SCOPE_TAG would be SELF.%K.name contains[c] %@". - indragie
Thank you for the comment. I changed it to %K but the behaviour didn't change - Diego A. Rincon
Don't you miss the ANY in your second predicate statement? I think you want to check if any of the tag names in your array contains the text... - Alexander

1 Answers

9
votes

First of all, if you substitute a keypath you should use %K as arg.

Further, I think you are missing the ANY argument in your second query. I think you want a result if any of the tag names contains your textSearch.

To get a better understanding of how predicates work, have a look at the Apple Documentation

I did a quick test and it is still working fine:

NSMutableArray *arrayContacts = [NSMutableArray array];

{
    AMContact *contact = [[AMContact alloc] init];
    NSMutableArray *arrayTags = [NSMutableArray array];
    {
        AMTags *tag = [[AMTags alloc] init];
        tag.name = @"Test";
        [arrayTags addObject:tag];
    }

    {
        AMTags *tag = [[AMTags alloc] init];
        tag.name = @"Te2st2";
        [arrayTags addObject:tag];
    }

    {
        AMTags *tag = [[AMTags alloc] init];
        tag.name = @"No";
        [arrayTags addObject:tag];
    }
    contact.tags = [arrayTags copy];
    [arrayContacts addObject:contact];
}

{
    AMContact *contact = [[AMContact alloc] init];
    NSMutableArray *arrayTags = [NSMutableArray array];
    {
        AMTags *tag = [[AMTags alloc] init];
        tag.name = @"Test";
        [arrayTags addObject:tag];
    }
    contact.tags = [arrayTags copy];
    [arrayContacts addObject:contact];
}
NSPredicate *pred = [NSPredicate predicateWithFormat:@"ANY SELF.%K.name contains[c] %@", @"tags", @"Test"];

NSArray *result = [arrayContacts filteredArrayUsingPredicate:pred];

NSLog(@"%@", result);