You’re reading Ry’s Objective-C Tutorial → Data Types |
NSNumber
The NSNumber class is a lightweight, object-oriented wrapper
around C’s numeric primitives. It’s main job is to store and
retrieve primitive values, and it comes with dedicated methods for each data
type:
NSNumber*aBool=[NSNumbernumberWithBool:NO];NSNumber*aChar=[NSNumbernumberWithChar:'z'];NSNumber*aUChar=[NSNumbernumberWithUnsignedChar:255];NSNumber*aShort=[NSNumbernumberWithShort:32767];NSNumber*aUShort=[NSNumbernumberWithUnsignedShort:65535];NSNumber*anInt=[NSNumbernumberWithInt:2147483647];NSNumber*aUInt=[NSNumbernumberWithUnsignedInt:4294967295];NSNumber*aLong=[NSNumbernumberWithLong:9223372036854775807];NSNumber*aULong=[NSNumbernumberWithUnsignedLong:18446744073709551615];NSNumber*aFloat=[NSNumbernumberWithFloat:26.99f];NSNumber*aDouble=[NSNumbernumberWithDouble:26.99];NSLog(@"%@",[aBoolboolValue]?@"YES":@"NO");NSLog(@"%c",[aCharcharValue]);NSLog(@"%hhu",[aUCharunsignedCharValue]);NSLog(@"%hi",[aShortshortValue]);NSLog(@"%hu",[aUShortunsignedShortValue]);NSLog(@"%i",[anIntintValue]);NSLog(@"%u",[aUIntunsignedIntValue]);NSLog(@"%li",[aLonglongValue]);NSLog(@"%lu",[aULongunsignedLongValue]);NSLog(@"%f",[aFloatfloatValue]);NSLog(@"%f",[aDoubledoubleValue]);
It may seem redundant to have an object-oriented version of all the C
primitives, but it’s necessary if you want to store numeric values in an
NSArray, NSDictionary, or any of the other Foundation
Framework collections. These classes require all of their elements to be
objects—they do not know how to interact with primitive values. In
addition, NSNumber makes it possible to pass numbers to methods
like performSelector:withObject:, as discussed in Selectors.
But, aside from the object-oriented interface, there are a few perks to
using NSNumber. For one, it provides a straightforward way to
convert between primitive data types or get an NSString
representation of the value:
NSNumber*anInt=[NSNumbernumberWithInt:42];floatasFloat=[anIntfloatValue];NSLog(@"%.2f",asFloat);NSString*asString=[anIntstringValue];NSLog(@"%@",asString);
And, like all Objective-C objects, NSNumber can be displayed
with the %@ format specifier, which means that you can forget
about all of the C-style specifiers introduced in the Primitives module. This makes life a tiny bit easier
when trying to debug values:
NSNumber*aUChar=[NSNumbernumberWithUnsignedChar:255];NSNumber*anInt=[NSNumbernumberWithInt:2147483647];NSNumber*aFloat=[NSNumbernumberWithFloat:26.99f];NSLog(@"%@",aUChar);NSLog(@"%@",anInt);NSLog(@"%@",aFloat);
Numeric Literals
Xcode 4.4 introduced numeric literals, which offer a much more convenient
alternative to the above factory methods. The NSNumber version of
BOOL’s, char’s, int’s
and double’s can all be created by simply prefixing the
corresponding primitive type with the @ symbol; however,
unsigned int’s, long’s, and
float’s must be appended with the U,
L, or F modifiers, as shown below.
NSNumber*aBool=@NO;NSNumber*aChar=@'z';NSNumber*anInt=@2147483647;NSNumber*aUInt=@4294967295U;NSNumber*aLong=@9223372036854775807L;NSNumber*aFloat=@26.99F;NSNumber*aDouble=@26.99;
In addition to literal values, it’s possible to box arbitrary C
expressions using the @() syntax. This makes it trivial to turn basic
arithmetic calculations into NSNumber objects:
doublex=24.0;NSNumber*result=@(x*.15);NSLog(@"%.2f",[resultdoubleValue]);
Immutability
It’s important to understand that NSNumber objects are
immutable—it’s not possible to change its associated value after
you create it. In this sense, an NSNumber instance acts exactly
like a primitive value: When you need a new double value, you
create a new literal—you don’t change an existing one.
From a practical standpoint, this means you need to create a new
NSNumber object every time you change its value. For example, the
following loop increments a counter object by adding to its
primitive value, then re-boxing it into a new NSNumber and
assigning it to the same variable.
NSNumber*counter=@0;for(inti=0;i<10;i++){counter=@([counterintValue]+1);NSLog(@"%@",counter);}
As you could probably imagine, this isn’t the most efficient way to
work with numbers. In real applications, you should limit yourself to primitive
numeric types for computationally intensive algorithms and wait as long as
possible to store the result in an NSNumber container.
Comparing Numbers
While it’s possible to directly compare NSNumber
pointers, the isEqualToNumber: method is a much more robust way to
check for equality. It guarantees that two values will compare equal,
even if they are stored in different objects. For example, the
following snippet shows a common case of pointer comparison failure.
NSNumber*anInt=@27;NSNumber*sameInt=@27U;// Pointer comparison (fails)if(anInt==sameInt){NSLog(@"They are the same object");}// Value comparison (succeeds)if([anIntisEqualToNumber:sameInt]){NSLog(@"They are the same value");}
If you need to check for inequalities, you can use the related
compare: method. Instead of a Boolean value, it returns an NSComparisonResult,
which is an enum that defines the relationship between the
operands:
| Return Value | Description |
|---|---|
NSOrderedAscending |
receiver < argument |
NSOrderedSame |
receiver == argument |
NSOrderedDescending |
receiver > argument |
The following example shows these enumerators in action.
NSNumber*anInt=@27;NSNumber*anotherInt=@42;NSComparisonResultresult=[anIntcompare:anotherInt];if(result==NSOrderedAscending){NSLog(@"27 < 42");}elseif(result==NSOrderedSame){NSLog(@"27 == 42");}elseif(result==NSOrderedDescending){NSLog(@"27 > 42");}
This kind of object-oriented comparison may not be as convenient as the
familiar <, ==, and > operators,
but abstracting them into methods affords a lot more flexibility to the
Foundation Framework classes.
![]() |
Be sure to check out Ry’s Cocoa Tutorial. This brand new guide is a complete walkthrough of Mac App development, and it leverages all of the Objective-C skills that we just discussed. Learn more › |
Mailing List
Sign up for my low-volume mailing list to find out when new content is released. Next up is a comprehensive Swift tutorial planned for late January.
You’ll only receive emails when new tutorials are released, and your contact information will never be shared with third parties. Click here to unsubscribe.
