A quick tip today on adding basic non-object types such as NSInteger
and BOOL
to Objective-C collection classes such as NSArray
and NSDictionary
.
Objective-C Primitive Data Types
The Objective-C language is a set of extensions to the standard C language. This means that many of the basic types are inherited from the underlying C language. This makes Objective-C different from some other object-oriented languages such as ruby where everything is an object.
The Cocoa Core Foundation framework defines NSInteger
and NSUInteger
types but if you look at the definitions in NSObjCRuntime.h
you will see that they are just typedefs for the underlying int
or unsigned int
C types. One additional basic data type that Objective-C does add is BOOL
but again if you take a look at its definition in objc.h you will see that BOOL
is also not an object, it is actually just a char
.
Adding Primitive Data Types to Collections
My guess is that most Cocoa and Cocoa Touch developers do not care how object-oriented Objective-C is. However the fact that not all types are objects can catch people out who are new to the language. Consider the following code to add some items to an array:
NSInteger score = 100;
BOOL flag = YES;
NSMutableArray *myArray = [NSArray array];
[myArray addObject:score];
[myArray addObject:flag];
This seems perfectly reasonable but both of the -addObject:
method calls generate compiler warnings:
warning: passing argument 1 of 'addObject:' makes pointer from
integer without a cast
The definition of addObject:
is as follows:
- (void)addObject:(id)anObject
As the definition suggests you can add any object you like to an array but it has to be an object. This discussion also applies to other Objective-C collection types such as NSMutableDictionary
and NSMutableSet
. Since neither NSInteger
or BOOL
are objects the compiler generates a warning to tip you off that something is probably wrong with your code.
The solution luckily is very simple. You need to first convert the integer and bool types to an object. The easiest way to do that is to convert them to an NSNumber
which is a full Objective-C object. The NSNumber
class has a number of class level factory methods which make creating an NSNumber
object quick and easy:
[myArray addObject:[NSNumber numberWithInteger:score]];
[myArray addObject:[NSNumber numberWithBool:flag]];
These class methods create autoreleased NSNumber
objects so we do not need to worry about calling release on these objects ourself. See this previous post for more discussion on Cocoa Factory Classes and Autorelease.
Retrieving Primitive Data Types from Collections
The process of extracting the integer and boolean types from the array is equally easy using the appropriate NSNumber
instance methods to access the numeric values. In this case we need to use -integerValue
and -boolValue
on the NSNumber
object returned from the array:
NSNumber *myScore = [myArray objectAtIndex:0];
NSInteger scoreValue = [myScore integerValue];
BOOL flagValue = [[myArray objectAtIndex:1] boolValue];