1
votes

I have a core data class, SSSLicense that has attributes like name and type. It inherits from an abstract entity called SSSArchivableEntity which has a boolean attribute named isArchived (among others).

I've already fetched the full set of license entities from the DB and am now trying to filter based on type and the isArchived flag. However, despite many variations of my predicate, I cannot get a valid result.

Here is the relevant code:

    NSSet *licenses = [person licenseList] ;

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(licenseType like %@) AND (isArchived == NO)",
                           lType];
NSSet *filteredLicenses = [licenses filteredSetUsingPredicate:predicate];

If I change my predicate to use another attribute of SSSLicense, say name (instead of isArchived), the predicate works. I even added a simple boolean attribute to SSSLicense and filtered using it successfully.

It seems like it has something to do with the fact that isArchived is an attribute of the abstract entity. Is there something special I need to do to filter with inherited attributes?

Thanks!

3
Try to rename the attribute. Some attribute names conflict with built-in properties of NSManagedObject.Martin R
Thanks, but that did not work. I changed the name of the attribute to 'fred', but still get the same result (no matching objects).Dan Nichols
the NSPredicate is not a NSString, you need to learn more about how you should use the %K and %@ format-specifiers for the predicates, or you can create a predicate with blocks which would be much more comfortable.holex
I have tried numerous variations including %K versus direct strings. I gave the above sample code since it was the simplest to explain. The sample code from Apple shows both and both work just fine IF the attributes are part of the concrete entity. It only fails if the attribute I test for is in the abstract entity.Dan Nichols
I have a similar issue, but with a String attribute in the abstract base entity. No idea why the predicate filters out everything.fabb

3 Answers

0
votes

Maybe hard-coding the value does not work. I recommend using the standard syntax:

[NSPredicate predicateWithFormat:
    @"(licenseType like %@) && (isArchived = %@)", lType, @(NO)];

If this does not work I would manually check the value of your isArchived property via sqlite3 command line tool or SQLite Manager plugin in Firefox. Maybe you are expecting a value there that has not been persisted.

If all these are verified it could be that you are reading the wrong values or displaying the wrong values although the predicate actually works.

0
votes

I'd rather prefer better the blocks instead of the format, hence I would try something like this:

[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
    return ([[evaluatedObject licenseType] rangeOfString:lType].location == NSNotFound && [[evaluatedObject isArchived] boolValue] == NO);
}];
0
votes

The issue turns out to be one of how the predicate tests the conditional versus a direct test via an if statement. My seed data created the license via direct setter calls and I was not explicitly setting isArchived to NO. Within the app, when a license was created it was being set. So, seed data was failing to be returned via the predicate. However, if I manually looped through the set and did a test via "[license isArchived] == NO" both the seed data and the app data were returned as expected.

My guess is that a direct boolean test checks for a valid 'YES' and if not there assumes NO whereas the predicate is explicitly checking YES=1 NO=0 (or however it is represented).