Objective c {NSDecimalNumber integerValue}在iOS8中表现异常

Objective c {NSDecimalNumber integerValue}在iOS8中表现异常,objective-c,ios8,nsdecimalnumber,Objective C,Ios8,Nsdecimalnumber,好的,团队,这很奇怪。[NSDecimalNumber integerValue]的行为异常 我坐在一个断点处,试图找出为什么我的应用程序的某些部分在iOS8中被破坏,我正在查看一个名为“timeSeconds”的变量。在Xcode变量视图中显示如下: _timeSeconds (NSDecimalNumber *) 344.514533996581994496 但当我在调试器中查询它时,我看到: (lldb) p [self.timeSeconds doubleValue] (doub

好的,团队,这很奇怪。[NSDecimalNumber integerValue]的行为异常

我坐在一个断点处,试图找出为什么我的应用程序的某些部分在iOS8中被破坏,我正在查看一个名为“timeSeconds”的变量。在Xcode变量视图中显示如下:

_timeSeconds    (NSDecimalNumber *) 344.514533996581994496
但当我在调试器中查询它时,我看到:

(lldb) p [self.timeSeconds doubleValue]
(double) $14 = 344.51453399658192
(lldb) p [self.timeSeconds intValue]
(int) $15 = 344
(lldb) p [self.timeSeconds integerValue]
(NSInteger) $16 = -5
(lldb) p (NSInteger)[self.timeSeconds intValue]
(NSInteger) $17 = 344
看到那个“-5”了吗?在我提交雷达文件之前,你们这些漂亮的人能复制或解释一下吗

以下是SSCCE:

NSDecimalNumber *n = [NSDecimalNumber decimalNumberWithString:@"344.514533996581994496"];
NSLog(@"%@", n); // 344.514533996581994496
NSLog(@"%ld", (long)[n intValue]); // 344
NSLog(@"%ld", (long)[n integerValue]); // -5
NSLog(@"%ld", (long)[n unsignedIntegerValue]); // 12
提前谢谢


Matthew

integerValue的结果令人惊讶,但据我所知,如文件所述:

NSDecimalNumber继承自NSNumber。在NSNumber的子类化注释中,说明 “…子类必须重写与声明的类型对应的访问器方法。例如,如果objCType的实现返回“i”,则必须重写intValue…”

objCType设置为内部指针,因此它应该与NSNumber相同

NSDecimal不会覆盖InterserValue。 它确实覆盖了doubleValue,因此应该可以正常工作


唯一让我感到奇怪的是:它似乎也没有覆盖intValue

多么大的错误啊!我发现自己被它欺骗了。所以,我们来总结一下dogsgods的回答:

不要:

NSInteger x = [myDecimalNumber integerValue];
相反,请执行以下操作:

NSInteger x = (NSInteger)[myDecimalNumber doubleValue];

使用
myDecimalNumber.intValue
而不是
integerValue

您可以很好地使用intValue或unsigneditvalue,但不能使用integerValue或unsigneditgervalue。下面是一个单元测试,它演示了这个问题,表明它与需要超过64位精度的数字有关:

//
//  NSDecimalNumberBugTests.m
//
//  Created by Lane Roathe on 6/1/17.
//  For Quicken, Inc.
//

#import <XCTest/XCTest.h>

@interface NSDecimalNumberBugTests : XCTestCase

@end

@implementation NSDecimalNumberBugTests

- (void)setUp {
    [super setUp];
    // Put setup code here. This method is called before the invocation of each test method in the class.
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
}

- (void)testBug {
    // Use XCTAssert and related functions to verify your tests produce the correct results.
    NSDecimalNumber* decimalLength;
    NSUInteger interval;

    // Start with a number that requires 65+ bits

    // This FAILS (interval is zero)
    decimalLength = [NSDecimalNumber decimalNumberWithString:@"1.8446744073709551616"];
    interval = decimalLength.unsignedIntegerValue;
    XCTAssert(interval == 1);

    // This Works, interval is 1
    interval = decimalLength.unsignedIntValue;
    XCTAssert(interval == 1);

    // Now test with a number that fits in 64 bits

    // This WORKS (interval is 1)
    decimalLength = [NSDecimalNumber decimalNumberWithString:@"1.8446744073709551615"];
    interval = decimalLength.unsignedIntegerValue;
    XCTAssert(interval == 1);
}

@end
//
//NSDecimalNumberBugTests.m
//
//由Lane Roath于2017年6月1日创建。
//为Quicken公司。
//
#进口
@接口NSDecimalNumberBugTests:XCTestCase
@结束
@NSDecimalNumberBugTests的实现
-(无效)设置{
[超级设置];
//将设置代码放在这里。在调用类中的每个测试方法之前调用此方法。
}
-(无效)拆卸{
//将拆卸代码放在这里。该方法在调用类中的每个测试方法后调用。
[超级撕裂];
}
-(void)testBug{
//使用XCTAssert和相关函数验证测试是否产生正确的结果。
N小数*小数长度;
整数区间;
//从一个需要65位以上的数字开始
//此操作失败(间隔为零)
decimalLength=[NSDecimalNumber decimalNumberWithString:@“1.8446744073709551616”];
间隔=decimalLength.unsignedIntegerValue;
xctasert(间隔==1);
//这有效,间隔为1
间隔=十进制长度。无符号值;
xctasert(间隔==1);
//现在用一个适合64位的数字进行测试
//这项工作(间隔为1)
decimalLength=[NSDecimalNumber decimalNumberWithString:@“1.8446744073709551615”];
间隔=decimalLength.unsignedIntegerValue;
xctasert(间隔==1);
}
@结束

Matthew-你发现了什么?iOS 8上的NSDecimalNumber在我的live应用程序中造成了巨大的问题!我认为你的思路是正确的。我想更好地理解这一点,如果您确实了解intValue,请发布您的答案。但我会继续奖励奖金,因为我认为这是正确的方向,我不希望奖金在没有奖励给你的情况下用完。这是一个相关的问题,其中有一个更具体的NSDecimal问题,可能与这个问题有关。