Wrappers for Numbers: NSNumber and Collections of Integers

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 Integer or Long and function as wrapper objects.

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

  1. Create a “raw” C/C++ array
  2. Use the Standard Template Library
  3. 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.

Further Reading

This entry was posted in Uncategorized. Bookmark the permalink.

Error: The ad management script is not properly configured for this user

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>