4
votes

I am learning Objective-C/Cocoa using the 4th edition of Cocoa Programming for Mac OSX. I apologize for the basic question but I'm one of those people that really need to understand the insides of everything in order for it to make sense to me and this book doesn't always do that to my needs. I've already picked up the basics of C++ and now I'm learning Obj-C so that is my background. This is a snippet of code that I'm learning...

for (i= 0; i < 10; i++) {
    NSNumber *newNumber = [[NSNumber alloc] initWithInt:(i * 3)];
    [array addObject:newNumber];
}

My question is why would you create instances of NSNumber to add to the array instead of just a single integer variable. It seems like it is just extra overhead creating a new instance each loop that could be avoided. But I'm sure the authors know what they are doing and there is a reason for it, could someone please explain?

3
That code assumes ARC is enabled (which it should be if you are just starting out).bbum
I barely understand what ARC is other than some form of memory management, but everything is nested in @autoreleasepool.Scott
BTW - use modern syntax. Inside the loop you just need [array addObject:@(i * 3)];.rmaddy
@Scott Even if nested in an autorelease pool, that'll leak. The alloc implies a +1 retain count. The addObject: implies a second +1 retain count. Releasing array will release that second +1. But something needs to balance the +1 of alloc. If you have ARC enabled, then it'll "just work". If not, then adding [newNumber release]; after the addObject: line would be correct.bbum
@Scott www.whentouseretaincount.com is actually quite the valuable tool to learning the innards of reference counting in ObjC. Even for the pure ARC app, it is still useful to understand.bbum

3 Answers

7
votes

NSArray can only hold objects, not primitive types. NSNumber and NSValue are used to wrap primitive types in objects, so they can be stored in foundation collections like NSArray, NSDictionary, and NSSet (and their mutable / ordered counterparts). As Peter Hosey points out in the comments:

The common term for this is "boxing" (as in boxing them up), and the inverse — extracting the primitive value from a box object — is unboxing.

2
votes

Because Core Foundation classes are not able to work directly with primitive types, they can deal only with NSObject instances (which are objects in OOP terms, not primitives)

That's why you are forced to wrap your int variable with a NSNumber (or NSData or NSValue). This certainly brings some overhead, indeed if you need performance critical code, I suggest you to use Objective-C++ and rely on STL (eg std::vector<int>).

I personally had to discard all core foundation classes in favour of STL for big parts of a game engine just because they couldn't keep it up when managing large amounts of primitive data.

1
votes

NSArray deals directly with pointers – and by extension, objects – whereas int is a primitive type. NSNumber exists to bridge this gap. An NSNumber can be cast from an int, float, or even a bool. The salient point is that it provides an object with a pointer, and that pointer can be added to the array.