views:

404

answers:

1

I always seem to run into trouble with NSDecimalNumber! Today, I get this error:

"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFNumber decimalNumberByDividingBy:withBehavior:]: unrecognized selector sent to instance 0xd1fb10'"

Here is the source of the error:

- (void)setUpInstance {
    static NSDecimalNumberHandler* roundingBehavior = nil;
    if (roundingBehavior == nil) {
        roundingBehavior = [[NSDecimalNumberHandler alloc] initWithRoundingMode:NSRoundDown scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
    }   
    NSDecimalNumber *amount = viewController.aDecimalNumber;
    NSDecimalNumber *actualValue = viewController.anotherDecimalNumber;
    integralPortion = [amount decimalNumberByDividingBy:actualValue withBehavior:roundingBehavior];
    ...
}

The docs define the method as:

-(NSDecimalNumber*)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber
                                withBehavior:(id<NSDecimalNumberBehaviors>)behavior

I must not be interpreting the "(id<NSDecimalNumberBehaviors>)behavior" argument correctly. Isn't that just ANY object as long as it conforms to the NSDecimalNumbersBehaviors protocol?

What am I'm doing wrong? Code examples would be very helpful.

Happy Friday!

+3  A: 

Today, I get this error: "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFNumber decimalNumberByDividingBy:withBehavior:]: unrecognized selector sent to instance 0xd1fb10'"

That means you're sending that message to a plain NSNumber (NSCFNumber behind the scenes). You can only send it to an NSDecimalNumber.

Note that how you declare the variables is irrelevant. You could declare amount as NSString *amount and you would get the exact same exception, including NSCFNumber as the class name, because it is an exception, which happens at run-time. (You would, of course, also get the compile-time warning about NSString and NSDecimalNumber not being interchangeable.)

Peter Hosey
So how can I be sure I'm working with an NSDecimalNumber?
Meltemi
Is viewController a class that you created? If so, make sure that aDecimalNumber is returning a NSDecimalNumber (if it's supposed to). Otherwise, use decimalNumberWithMantissa:exponent:isNegative: to create an NSDecimalNumber from the value you are getting, and then work with that.
smorgan
Meltemi: Just don't ever assign a plain NSNumber to the view controller's `aDecimalNumber` property. If you're saving and restoring the value, use its string representation for the storage format. (Saving to a property list will *not* work, since it will both save and restore as a plain NSNumber would, with attendant loss of precision.)
Peter Hosey