Search code examples
cocoacore-datanspredicateeditornspredicateeditorrow

NSPredicateEditorRowTemplate and CoreData


I am trying to generate predicate editor templates for my Core Data entities. In my code I have the following:

 NSEntityDescription *descrip = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:managedObjectContext];
   NSArray *templates = [NSPredicateEditorRowTemplate templatesWithAttributeKeyPaths:[NSArray arrayWithObjects:@"name", @"age", nil] inEntityDescription:descrip];

   [ibPredicateEditor setRowTemplates: templates];

   NSPredicate *p = [NSPredicate predicateWithFormat:@"name like 'John'"];

   [ibPredicateEditor setObjectValue:p];

Printing out the contents of the templates array gives me the following:

CFArray 0x1002d7400 [0x7fff70ff5f20] {type = immutable, count = 2, values = ( 0 : NSPredicateEditorRowTemplate 0x10025c090: [name] [99, 4, 5, 8, 9] NSStringAttributeType 1 : NSPredicateEditorRowTemplate 0x1002d2dc0: [age] [4, 5, 0, 2, 1, 3] NSInteger16AttributeType )}

When this code executes I get the following on the console:

Warning - unable to find template matching predicate name LIKE "John"

The interface for doing this looks extremely straight forward, so I can't seem to figure out what I am doing wrong. Any help would be greatly appreciated!

EDIT

My original issue was that I was using the LIKE operator when my templates did not support it. However I am confused about why I get a similar warning when passing in a compound predicate into the editor.

NSPredicate *p = [NSPredicate predicateWithFormat:@"name CONTAINS 'John'"];
NSPredicate *p2 = [NSPredicate predicateWithFormat:@"name CONTAINS 'Jo'"];
NSPredicate *final = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:p, p2, nil]];
[ibPredicateEditor setObjectValue: final];

OR

NSPredicate *final = [NSCompoundPredicate orPredicateWithSubpredicates:[NSArray arrayWithObjects:p, p2, nil]];
[ibPredicateEditor setObjectValue: final];

Both of these produce similar warnings as my initial issue. However, I find it odd that I can use a single predicate and build a compound and predicate, but I can't pass a prebuilt compound and predicate into the editor.


Solution

  • The default templates supplied by NSPredicateEditorRowTemplate for NSString key-paths do not support comparisons with the LIKE operator.

    In the templates you generated there is a list of the operators it does support:

    NSPredicateEditorRowTemplate 0x10025c090: [name] [99, 4, 5, 8, 9] NSStringAttributeType
    

    [99, 4, 5, 8, 9] indicates that the name NSString attribute supports:

    4 – Equal To
    5 – Not Equal To
    8 – Begins With
    9 – Ends With
    99 – Contains

    (found in NSComparisonPredicate.h)

    CONTAINS is similar to LIKE without % and _ substitutions. If you require that you can always initialize your own template array.

    The syntax is a bit verbose.

    NSExpression *nameExpression = [NSExpression expressionForKeyPath:@"name"];
    NSArray *operators = [NSArray arrayWithObjects:
          [NSNumber numberWithInt: NSEqualToPredicateOperatorType],
          [NSNumber numberWithInt:NSNotEqualToPredicateOperatorType],
          [NSNumber numberWithInt:NSLikePredicateOperatorType],
          [NSNumber numberWithInt:NSBeginsWithPredicateOperatorType],
          [NSNumber numberWithInt:NSEndsWithPredicateOperatorType],
          [NSNumber numberWithInt:NSContainsPredicateOperatorType],
          nil];
    
    NSUInteger options = (NSCaseInsensitivePredicateOption |
                          NSDiacriticInsensitivePredicateOption);
    
    NSPredicateEditorRowTemplate *template = [[NSPredicateEditorRowTemplate alloc]
          initWithLeftExpressions:[NSArray arrayWithObject:nameExpression]
          rightExpressionAttributeType:NSStringAttributeType
          modifier:NSDirectPredicateModifier
          operators:operators
          options:options];