objective-ccore-datanspredicateios8.1xcode6.1.1

iOS Predicate for CoreData with long long values were not precise enough


This app I have been building runs on iPad and I have been testing it on iOS8.1 using XCode 6.1.1. I am having a problem where I try extract records by comparing the date of a record in milliseconds. The records are stored using CoreData.

The firstDate of a record is declared as follows

record.firstDate = [NSNumber numberWithLongLong:1423288915464];

The firstDate is declared in the .h file of the record in this way:

@property (nonatomic, retain) NSNumber * firstDate;

The predicate is declared this way:

NSNumber* prevStartMillis = [NSNumber numberWithLongLong:1423324800000];
NSNumber* prevEndMillis = [NSNumber numberWithLongLong:1423411199000];    

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"firstDate >= %lld AND firstDate < %lld", [prevStartMillis longLongValue], prevEndMillis longLongValue]];

I did get some of the records with firstDate that falls within the specified range. However, I get a few records that do not fall within the specified range like these 3 of the many:

...
FirstDate:1423288915464
FirstDate:1423282909663
FirstDate:1423286413320
...

Previously I had a similar problem on another app for iPhone 6 iOS8.1 using XCode 6.1.1 as well. I was able to solve it by declaring the predicates with %lld for long long values. However, when I use the same code, it fails on iPad. Does anyone know what is it that I did wrong? Thanks in advance!

EDIT 1: Workaround
I have a workaround (though not very efficient). Here is the code snippet after I extract the records if anyone is wondering:

NSMutableArray* validRecords = [[NSMutableArray alloc] init];

for(Record* record in results) {
    if([record.firstDate longLongValue] >= [prevStartMillis longLongValue] && [record.firstDate longLongValue] <= [prevEndMillis longLongValue])
        [validRecords addObject:record];
}   

Solution

  • You don't have to extract long from NSNumber like you do. You can use NSNumber objects explicitly to create predicate

    NSNumber* prevStartMillis = [NSNumber numberWithLongLong:1423324800000];
    NSNumber* prevEndMillis = [NSNumber numberWithLongLong:1423411199000];    
    
    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"firstDate >= %@ AND firstDate < %@", prevStartMillis, prevEndMillis];
    

    EDITED: I've reviewed your code again and figured out that numbers that you had wrote are out of your range. Just let's write your long numbers in shorter manner:

    NSNumber* prevStartMillis = /*14233e+8*/;
    NSNumber* prevEndMillis = /*14234e+8*/;
    

    and this numbers are out of range:

    ...
    FirstDate:14232e+8
    FirstDate:14232e+8
    FirstDate:14232e+8
    ...
    

    So now it's easy to notice that this numbers are 'a bit' smaller to satisfy you condition