6
votes

tl;dr: type something here that won't crash if birthDate is nil:

xcdatamodel screenshot


I have an entity with a birthDate attribute and a fetched property with the following predicate, typed straight into the xcdatamodel file:

$FETCH_SOURCE.birthDate > birthDate

This happily returns a list of managed objects older than FETCH_SOURCE (the managed object where the fetch request is happening). But birthDate is optional, and if the birthDate for FETCH_SOURCE is nil...

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'can't use NULL on left hand side'

Note that it's fine if the attribute is nil for the object being compared. If I swap the arguments of the predicate:

birthDate < $FETCH_SOURCE.birthDate

...I get the same error. Trying to test it for nil:

(birthDate != nil AND birthDate < $FETCH_SOURCE.birthDate)

...gives...

'NSInvalidArgumentException', reason: 'illegal comparison with NULL'

Google hasn't heard of either of those errors so I'm thinking this is a recent state of affairs. The problem remains when it's a String being compared for equivalence, or whatever. Is there a way to fix this in the predicate so it correctly returns an empty list? Thanks.

Edit: To be clear, the question is whether it's possible to fix this crash in the predicate in the xcdatamodel file.

Update: The crash specifically happens when the Relationship fault for the NSFetchedPropertyDescription is triggered by trying to read anything about it, presumably because it doesn't attempt to run the predicate till then. It isn't nil however, and can be checked for nil without crashing.

2
Icaro, they have similar title keywords but are completely different questions. Are you a bot? ;)DenverCoder9
No just trying to help, but wouldn't that be cool! ;) Anyway my understand from the last question was you can compare with nil but you cannot use a nil value to compare with something, and that seems to be what my testing show, but I will let the explanation to someone else as I don't really know why!Icaro
I see what you mean, but it looks like that question is about passing nil in a variable argument list, which just happened to be being done while formatting a predicate, rather than having the nil in the actual predicate. On the contrary, it supports my suspicions that my problem is a new one, as Core Data was quite happy with a predicate of "parentFolder == nil" in Jul 10 '14.DenverCoder9
Have you tried using birthDate != [NSNull null]Lneuner

2 Answers

6
votes

I can't find any way to amend the predicate of the fetched property to avoid this error, but one workaround is to implement a custom getter for the olderHeroes fetched property. This should return an empty array if the birthDate is nil.

var olderHeroes: NSArray {
    var array : NSArray
    if self.birthDate == nil {
        array = NSArray()
    } else {
        self.willAccessValueForKey("olderHeroes")
        array = self.primitiveValueForKey("olderHeroes") as! NSArray
        self.didAccessValueForKey("olderHeroes")
    }
    return array
}

Or in Objective-C:

-(NSArray *)olderHeroes {
    NSArray *array;
    if (self.birthDate == nil) {
        array = [NSArray array];
    } else {
        [self willAccessValueForKey:@"olderHeroes"];
        array = [self primitiveValueForKey:@"olderHeroes"];
        [self didAccessValueForKey:@"olderHeroes"];
    }
    return array;
}

(These snippets go in the implementation file for the subclass of the FETCH_SOURCE entity).

2
votes

If you want to have results containing either a nil value or it has to be greater or smaller than a certain date use the following:

((birthDate == nil) OR (birthDate < %@))

This works for me. I hope this is what you're asking. Had a bit of trouble understanding your question.

If you're asking to check a variable you're passing in the predicate, might the following work (untested):

(($FETCH_SOURCE.birthDate == nil && birthDate == nil) OR ($FETCH_SOURCE.birthDate < birthDate))