【问题标题】:{NSDecimalNumber integerValue} behaving strangely in iOS8{NSDecimalNumber integerValue} 在 iOS8 中表现异常
【发布时间】:2014-09-06 22:52:34
【问题描述】:

好的团队,这很奇怪。 [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

提前致谢!

马修

【问题讨论】:

  • 马修 - 你发现了什么? iOS 8 上的 NSDecimalNumber 在我的实时应用程序中造成了巨大的问题!

标签: objective-c ios8 nsdecimalnumber


【解决方案1】:

integerValue 的结果令人惊讶,但据我所知,记录如下:

NSDecimalNumber 继承自 NSNumber。在 NSNumber 的子类注释中指出 "...子类必须覆盖与声明类型对应的访问器方法——例如,如果您的 objCType 实现返回“i”,则必须覆盖 intValue ..."

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

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

唯一让我好奇的是:它似乎也没有覆盖 intValue ...

【讨论】:

  • 我认为你绝对是在正确的轨道上。我想更好地理解这一点,如果您确实了解 intValue,请发布您的答案。但我会继续奖励赏金,因为我认为这是正确的方向,我不希望赏金在没有奖励给你的情况下用完。
  • 这是一个相关问题,其中有一个更具体的 NSDecimal 问题可能与此问题有关。 stackoverflow.com/questions/26741233/…
【解决方案2】:

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

不要:

NSInteger x = [myDecimalNumber integerValue];

相反,这样做:

NSInteger x = (NSInteger)[myDecimalNumber doubleValue];

【讨论】:

    【解决方案3】:

    使用myDecimalNumber.intValue 而不是integerValue

    【讨论】:

      【解决方案4】:

      你可以使用 intValue 或 unsignedIntValue 就好了,但是 NOT integerValue 或 unsignedIntegerValue。这是一个演示该问题的单元测试,表明它与需要超过 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
      

      【讨论】:

        猜你喜欢
        • 2014-10-27
        • 1970-01-01
        • 1970-01-01
        • 2014-12-08
        • 2016-12-07
        • 1970-01-01
        • 2022-01-16
        相关资源
        最近更新 更多