In the Java programming language there are both raw and wrapper objects to represent numbers. For example, int and Integer, double and Double, etc. If one wanted to add a numeric object to a Collection object, it required using the wrapper object rather than the raw type.
With the introduction of autoboxing in Java 1.5, moving between these types would largely be handled by the compiler, but there is still a distinction.
Just as with null types, Objective-C also requires that you wrap raw types before inserting them into objects or using them in variable argument lists where the type id is expected. To help us with this, cocoa provides NSNumber.
There is a great deal of confusion among newcomers on the Apple developer forums and other developer-driven communities because of typedefs such as NSInteger and NSUInteger. They expect that these would work like
In actuality these are just ways of following the rule “avoid raw C types.” You can find their definition in NSObjCRuntime.h:
1 2 3 4 5 6 7 8 | #if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 typedef long NSInteger; typedef unsigned long NSUInteger; #else typedef int NSInteger; typedef unsigned int NSUInteger; #endif |
These are there for convenience, especially when combined with NSIntegerMax, NSIntegerMin, etc.
When we want to create a collection of NSIntegers (or doubles, longs, etc), we have three main options options:
Options
- Create a “raw” C/C++ array
- Use the Standard Template Library
- Wrap the value with NSNumber and use a Cocoa collection
Raw C Arrays
Many times all that the developer needs is an array of numbers that can be processed quickly. In these cases it can be best just to use a straight C/C++ array. For example, this code creates an array of NSInteger and then stores the square of the index:
1 2 3 4 5 6 7 8 9 10 | size_t size = 10; NSInteger *array = (NSInteger *)calloc(size, sizeof(NSInteger)); for(NSInteger i = 0; i < size; i++) { array[i] = i*i; } free(array); |
Standard Template Library
After setting up to use the STL the STL can be used the same way it would be in C++, just using NSInteger in the template:
1 2 3 4 5 | std::vector<NSInteger> instance; instance.push_back(1); instance.push_back(2); instance.push_back(3); |
This approach is significantly more robust than using straight arrays and has the advantage of that everything does not need to be wrapped. On the other hand, it does not provide the convenience of working with Objective-C types and still needs to be converted to interact with Cocoa libraries.
Using NSNumber as a Wrapper
The final option, and the most robust, is to use Cocoa’s built-in libraries and wrap the NSInteger values in a NSNumber:
[NSNumber numberWithInteger:myInt]; |
NSNumber is a subclass of NSValue and it can store any of the basic numeric types. It should also be noted that NSDecimalNumber is a subclass of NSNumber.
NSNumber contains a variety of useful functions, but it does not actually contain the facilities for basic mathematical operations. To work with the numbers you will need to “unwrap” them once they get to their destination.