iOS 具有 long long 值的 CoreData 谓词不够精确
iOS Predicate for CoreData with long long values were not precise enough
我一直在构建的这个应用程序在 iPad 上运行,我一直在使用 XCode 6.1.1 在 iOS8.1 上测试它。我遇到了一个问题,我尝试通过比较以毫秒为单位的记录日期来提取记录。记录使用 CoreData 存储。
一条记录的firstDate声明如下
record.firstDate = [NSNumber numberWithLongLong:1423288915464];
firstDate在记录的.h文件中是这样声明的:
@property (nonatomic, retain) NSNumber * firstDate;
谓词是这样声明的:
NSNumber* prevStartMillis = [NSNumber numberWithLongLong:1423324800000];
NSNumber* prevEndMillis = [NSNumber numberWithLongLong:1423411199000];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"firstDate >= %lld AND firstDate < %lld", [prevStartMillis longLongValue], prevEndMillis longLongValue]];
我确实得到了一些 firstDate 在指定范围内的记录。但是,我得到了一些不在指定范围内的记录,例如许多记录中的这 3 个:
...
FirstDate:1423288915464
FirstDate:1423282909663
FirstDate:1423286413320
...
以前我在另一个应用程序 iPhone 6 iOS8.1 使用 XCode 6.1.1 时也遇到过类似的问题。我能够通过为 long long 值声明带有 %lld 的谓词来解决它。但是,当我使用相同的代码时,它在 iPad 上失败了。有谁知道我做错了什么?提前致谢!
编辑 1:解决方法
我有一个解决方法(虽然效率不高)。如果有人想知道,这是我提取记录后的代码片段:
NSMutableArray* validRecords = [[NSMutableArray alloc] init];
for(Record* record in results) {
if([record.firstDate longLongValue] >= [prevStartMillis longLongValue] && [record.firstDate longLongValue] <= [prevEndMillis longLongValue])
[validRecords addObject:record];
}
看起来像是它的有符号和无符号值问题。
您可以使用 %llu 并检查它是否有效。
解决方案是在我检索记录后使用 if 语句检查日期(请参阅问题中的编辑 1)
您不必像以前那样从 NSNumber
中提取 long
。
您可以显式使用 NSNumber 对象来创建 predicate
NSNumber* prevStartMillis = [NSNumber numberWithLongLong:1423324800000];
NSNumber* prevEndMillis = [NSNumber numberWithLongLong:1423411199000];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"firstDate >= %@ AND firstDate < %@", prevStartMillis, prevEndMillis];
已编辑:
我再次检查了你的代码,发现你写的数字超出了你的范围。让我们以更短的方式写下您的长号码:
NSNumber* prevStartMillis = /*14233e+8*/;
NSNumber* prevEndMillis = /*14234e+8*/;
并且这个数字超出范围:
...
FirstDate:14232e+8
FirstDate:14232e+8
FirstDate:14232e+8
...
所以现在很容易注意到这个数字 'a bit' 更小以满足您的条件
我一直在构建的这个应用程序在 iPad 上运行,我一直在使用 XCode 6.1.1 在 iOS8.1 上测试它。我遇到了一个问题,我尝试通过比较以毫秒为单位的记录日期来提取记录。记录使用 CoreData 存储。
一条记录的firstDate声明如下
record.firstDate = [NSNumber numberWithLongLong:1423288915464];
firstDate在记录的.h文件中是这样声明的:
@property (nonatomic, retain) NSNumber * firstDate;
谓词是这样声明的:
NSNumber* prevStartMillis = [NSNumber numberWithLongLong:1423324800000];
NSNumber* prevEndMillis = [NSNumber numberWithLongLong:1423411199000];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"firstDate >= %lld AND firstDate < %lld", [prevStartMillis longLongValue], prevEndMillis longLongValue]];
我确实得到了一些 firstDate 在指定范围内的记录。但是,我得到了一些不在指定范围内的记录,例如许多记录中的这 3 个:
...
FirstDate:1423288915464
FirstDate:1423282909663
FirstDate:1423286413320
...
以前我在另一个应用程序 iPhone 6 iOS8.1 使用 XCode 6.1.1 时也遇到过类似的问题。我能够通过为 long long 值声明带有 %lld 的谓词来解决它。但是,当我使用相同的代码时,它在 iPad 上失败了。有谁知道我做错了什么?提前致谢!
编辑 1:解决方法
我有一个解决方法(虽然效率不高)。如果有人想知道,这是我提取记录后的代码片段:
NSMutableArray* validRecords = [[NSMutableArray alloc] init];
for(Record* record in results) {
if([record.firstDate longLongValue] >= [prevStartMillis longLongValue] && [record.firstDate longLongValue] <= [prevEndMillis longLongValue])
[validRecords addObject:record];
}
看起来像是它的有符号和无符号值问题。 您可以使用 %llu 并检查它是否有效。
解决方案是在我检索记录后使用 if 语句检查日期(请参阅问题中的编辑 1)
您不必像以前那样从 NSNumber
中提取 long
。
您可以显式使用 NSNumber 对象来创建 predicate
NSNumber* prevStartMillis = [NSNumber numberWithLongLong:1423324800000];
NSNumber* prevEndMillis = [NSNumber numberWithLongLong:1423411199000];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"firstDate >= %@ AND firstDate < %@", prevStartMillis, prevEndMillis];
已编辑: 我再次检查了你的代码,发现你写的数字超出了你的范围。让我们以更短的方式写下您的长号码:
NSNumber* prevStartMillis = /*14233e+8*/;
NSNumber* prevEndMillis = /*14234e+8*/;
并且这个数字超出范围:
...
FirstDate:14232e+8
FirstDate:14232e+8
FirstDate:14232e+8
...
所以现在很容易注意到这个数字 'a bit' 更小以满足您的条件