我有一个Int64(long-long)uniqueID作为JSON文件中的数字传递。
{ "id1" : 4627596562884205957 }
NSJSONSerialization
始终在NSDictionary属性中返回NSNumber (double)
。这应该是Int64数字NSNumber (long-long)
,因为double会丢失所需精度的几位数。
它导致失败,因为代码将反序列化的值(double)与正确的值(Int64)进行比较,并且对于两个数字非常接近但仍然不同的情况,它们比较相等,即错误的逻辑。
可以NSJSONSerialization
配置为此属性返回正确的NSNumber(long-long)
,而不是错误的double
吗?
可以从long-long
中提取NSNumber(double)
值,然后将其强制转换为新的NSNumber(long-long)
吗?它似乎有效,但我不相信它。
以下显示错误。
- (void) doJSONDoubleVsInt64Comparison
{
// our primary Int64
int64_t aId1 = 4627596562884205957;
// put it into a JSON string, then read it into a dictionary.
NSString *jsonInputString = [NSString stringWithFormat:@"{ \"id1\" : %lld }", aId1];
NSData *jsonData = [jsonInputString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:false];
NSDictionary *asDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];
// the number after being deserialized from the JSON string
NSNumber *id1Number = [asDictionary objectForKey:@"id1"];
// the NSNumber is of type 'double' (not long-long as expected)
[self logNSNumber:id1Number named:@"id1"];
// get a DIFFERENT Int64 that varies only slightly
int64_t aId2 = 4627596562884205592;
NSNumber *id2Number = [NSNumber numberWithLongLong:aId2];
// This is of type Int64 (long-long) as expected.
[self logNSNumber:id2Number named:@"id2"];
// id1 and id2 are not equal numbers, but this comparison returns TRUE - why?
if( [id1Number isEqualToNumber:id2Number] )
{
// we incorrectly hit this condition.
NSLog(@"ERROR: id1 and id2 were reported to be equal, but they are different numbers.");
}
else{
NSLog(@"OK: id1 and id2 are not equal, as expected.");
}
// pull the long-long from the double - force it to be an Int64
NSNumber *id1NumberAsInt64 = [NSNumber numberWithLongLong:id1Number.longLongValue];
// the comparison now works.
[self logNSNumber:id1NumberAsInt64 named:@"id1AsInt64"];
if( [id1NumberAsInt64 isEqualToNumber:id2Number] )
{
NSLog(@"ERROR: id1 and id2 were reported to be equal, but they are different.");
}
else{
NSLog(@"OK: id1 and id2 are not equal, as expected.");
}
}
- (void)logNSNumber:(NSNumber *)aNumber named:(NSString *)name
{
CFNumberType numberType = CFNumberGetType((CFNumberRef)aNumber);
switch ( numberType )
{
case kCFNumberSInt64Type:
NSLog(@"%@ returned as an Int64", name); // does NOT hit this
break;
case kCFNumberDoubleType:
NSLog(@"%@ returned as a double", name); // hits this
break;
default:
NSLog(@"%@ NumberType = %ld", name, numberType );
break;
}
}