与NSNumber(Int64)相比,NSJSONSerialization返回NSNumber(double)导致失败

时间:2017-08-08 20:06:37

标签: objective-c nsjsonserialization

我有一个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;
    }
}

0 个答案:

没有答案