Objective c {NSDecimalNumber integerValue}在iOS8中表现异常
好的,团队,这很奇怪。[NSDecimalNumber integerValue]的行为异常 我坐在一个断点处,试图找出为什么我的应用程序的某些部分在iOS8中被破坏,我正在查看一个名为“timeSeconds”的变量。在Xcode变量视图中显示如下: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
_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
提前谢谢
MatthewintegerValue的结果令人惊讶,但据我所知,如文件所述: 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问题,可能与这个问题有关。