1.22. Allocating and Making Use of Numbers

Problem

You need to use integral values or encapsulate numbers in objects.

Solution

Use NSNumber for an object-oriented approach to handling numbers. If you require simple numbers (non-objects), use NSInteger to hold signed (positive and negative) values, NSUInteger to hold unsigned (only positive or zero) values, and CGFloat and double to hold floating point values.

Discussion

Just as we place strings inside instances of NSString, we can place numbers inside instances of NSNumber. Why, you might ask? The answer is simple: to allow an object to carry the value of our numbers so that we can save this value to disk easily, load it from disk, and simply allow a single object to carry signed and unsigned integral and floating point values, without the need for typecasting or defining multiple variables. The possibilities are virtually endless.

Let’s have a look at constructing instances of NSNumber:

NSNumber *signedNumber = [NSNumber numberWithInteger:-123456];
NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123456];
NSNumber *floatNumber = [NSNumber numberWithFloat:123456.123456f];
NSNumber *doubleNumber = [NSNumber numberWithDouble:123456.1234567890];

Just as we placed signed and unsigned integers and floating point values into an instance of NSNumber class, we can retrieve those values back using some really handy instance methods of NSNumber class, as shown here:

NSNumber *signedNumber = [NSNumber numberWithInteger:-123456];
NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123456];
NSNumber *floatNumber = [NSNumber numberWithFloat:123.123456f];
NSNumber *doubleNumber = [NSNumber numberWithDouble:123.1234567890];

NSInteger signedValue = [signedNumber integerValue];
NSUInteger unsignedValue = [unsignedNumber unsignedIntegerValue];
CGFloat floatValue = [floatNumber floatValue];
double doubleValue = [doubleNumber doubleValue];

NSLog(@"signedValue  = %ld, \n"\
      "unsignedValue = %lu  \n"\
      "floatValue    = %f   \n"\
      "doubleValue   = %f",
      (long)signedValue,
      (unsigned long)unsignedValue,
      floatValue,
      doubleValue);

Here are the methods of NSNumber that we used in this code to actually generate instances of NSNumber class:

numberWithInteger:

Encapsulates an integer into an instance of NSNumber.

numberWithUnsignedInteger:

Encapsulates an unsigned integer (only positive or zero numbers) into an instance of NSNumber.

numberWithFloat:

Encapsulates a floating point value into an instance of NSNumber.

numberWithDouble:

Encapsulates a double value into an instance of NSNumber.

And here are the methods which we used to extract pure numbers from instances of NSNumber:

integerValue

Returns an integer of type NSInteger from the NSNumber on which this method is called.

unsignedIntegerValue

Returns an unsigned integer of type NSUInteger from the NSNumber on which this method is called.

floatValue

Returns a floating point value of type CGFloat from the NSNumber on which this method is called.

doubleValue

Returns a double value of type double from the NSNumber on which this method is called.

If you want to convert a number to a string, simply convert it to any of the raw integral/float values that you think can contain the whole of that number, and then format your string using a format identifier that suits your data. For instance, to turn an unsigned integer into an instance of NSString, you can use the %lu format specifier, like so:

NSNumber *unsignedNumber = [NSNumber numberWithUnsignedInteger:123456];

/* Convert an unsigned integer inside an NSNumber to NSString */
NSString *numberInString =
  [NSString stringWithFormat:@"%lu",
   (unsigned long)[unsignedNumber unsignedIntegerValue]];

NSLog(@"numberInString = %@", numberInString);

Keep in mind that any class method of NSNumber class that starts with numberWith returns an autorelease instance of that NSNumber. To remove the burden on your autorelease pools, you can use the initWith... methods of the NSNumber class after allocating your number, like so:

NSNumber *unsignedNumber =
  [[NSNumber alloc] initWithUnsignedInteger:123456];

In this example, the unsignedNumber local variable will be disposed of, with a single release method sent to, after the scope of the current method in which this number is allocated and initialized finishes. The code for this will be added to our code, by the compiler and we won’t have to do anything extra. However, had we simply used the numberWithUnsignedInteger: class method of the NSNumber, we would have left the burden of releasing this value to the autorelease pool at runtime rather than leaving the burden on the compiler at compile time.

Get iOS 5 Programming Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.