## 57: Initialising NSDecimalNumber

#### Problem: We want to initialise NSDecimalNumber to a numeric value and do not see a way of doing it in the NSDecimalNumber documentation.

This example arises out of a discussion on the Cocoa-dev mailing list. I suggest one starts here.

### Answer: Examine the documentation further up the inheritance hierarchy.

The documentation for NSDecimalNumber shows four ways of creating a new NSDecimalNumber object. These are the methods defined for this NSDecimalNumber specialisation of NSNumber, i.e. NSDecimalNumber inherits from NSNumber.

Because NSDecimalNumber inherits from NSNumber this means that we can also create a NSDecimalNumber object using the methods defined for NSNumber.

#### NSDecimalNumber object creation methods

+ decimalNumberWithDecimal:
+ decimalNumberWithMantissa:exponent:isNegative:
+ decimalNumberWithString:
+ decimalNumberWithString:locale:

#### NSNumber object creation methods

+ numberWithBool:
+ numberWithChar:
+ numberWithDouble:
+ numberWithFloat:
+ numberWithInt:
+ numberWithInteger:
+ numberWithLong:
+ numberWithLongLong:
+ numberWithShort:
+ numberWithUnsignedChar:
+ numberWithUnsignedInt:
+ numberWithUnsignedInteger:
+ numberWithUnsignedLong:
+ numberWithUnsignedLongLong:
+ numberWithUnsignedShort:

#### Example Code showing some different ways of creating NSDecimalNumber objects

// main.m ##import int main(int argc, char *argv[]) { NSDecimalNumber *myDecimalObj = [[NSDecimalNumber alloc] initWithString:@"23.30"]; NSLog(@"myDecimalObj doubleValue=%6.3f",[myDecimalObj doubleValue]); CGFloat myCGFloatValue = 43.4; NSDecimalNumber *myOtherDecimalObj = [[NSDecimalNumber alloc] initWithFloat:myCGFloatValue]; NSLog(@"myOtherDecimalObj doubleValue=%6.3f",[myOtherDecimalObj doubleValue]); }

#### But what happens if we use NSValue object creation methods?

NSNumber inherits from NSValue which is a wrapper for a C or Objective-C data item. As far as I have been able to determine through (limited) experimentation defining an NSNumber or NSDecimalNumber using one of the NSValue method calls does not work.

For instance whilst the following code works:

float myfloat = 123.0; NSDecimalNumber *myNSValueObj = [[NSValue alloc] initWithBytes:&myfloat objCType:@encode(float *)]; float myNewFloat; [myNSValueObj getValue:&myNewFloat]; NSLog(@"myNSValueObj floatValue=%6.3f",myNewFloat);

The following does not:

float myOtherFloat = 543.21; NSDecimalNumber *myEncodedFloatDecimalObj = [[NSDecimalNumber alloc] initWithBytes:&myOtherFloat objCType:@encode(float *)]; NSLog(@"myEncodedFloatDecimalObj doubleValue=%6.3f", [myEncodedFloatDecimalObj doubleValue]);

The probable reason, if I understand the documentation, is that NSNumber is a class cluster. This has the consequence that it doesn't store the number, that is done by one of the cluster component classes , e.g. something like IntClass, FloatClass, etc. Though the following quote from the class cluster documentation refers to an example and not to NSNumber I think it likely that it applies nevertheless.

Number is the abstract superclass that declares in its methods the operations common to its subclasses. However, it doesn't declare an instance variable to store a number. The subclasses declare such instance variables and share in the programmatic interface declared by Number.

It follows then that a data pointer, e.g. to an int or a float, stored within the NSValue part of an instance of NSNumber will not be used by the component classes of NSNumber.

Note: a list of Objective-C compiler directives such as @encode is to be found here.