Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

{NSDecimalNumber integerValue} behaving strangely in iOS8

OK team, this is weird. [NSDecimalNumber integerValue] is behaving strangely.

I'm sat at a breakpoint, trying to figure out why some parts of my app are broken in iOS8, and I'm looking at a variable called "timeSeconds". It appears like this in the Xcode Variables View:

_timeSeconds    (NSDecimalNumber *) 344.514533996581994496

But when I query it in the debugger, I see this:

(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

See that "-5"? Can any of you beautiful people reproduce or explain that, before I file a radar?

Here's the 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

Thanks in advance!

Matthew

like image 543
Matthew Avatar asked Sep 06 '14 22:09

Matthew


2 Answers

The result for integerValue is surprising, but from what I understand as documented:

NSDecimalNumber inherits from NSNumber. In the subclassing notes from NSNumber it is stated that "... subclass must override the accessor method that corresponds to the declared type—for example, if your implementation of objCType returns “i”, you must override intValue ..."

objCType is set to the inner pointer, so it should be the same as for NSNumber.

NSDecimal does not override intergerValue. It does override doubleValue, so that should work fine.

The only thing that makes me wonder: it seems it does not override intValue either ...

like image 52
dogsgod Avatar answered Oct 25 '22 21:10

dogsgod


What a great bug! I just found myself tricked by it. So, just to conclude dogsgods answer:

Do NOT:

NSInteger x = [myDecimalNumber integerValue];

Instead, do THIS:

NSInteger x = (NSInteger)[myDecimalNumber doubleValue];
like image 28
Lukas Kalinski Avatar answered Oct 25 '22 22:10

Lukas Kalinski