views:

9880

answers:

3

What's the difference between NSNumber and NSInteger? Are there more primitives like these that I should know about/use? Is there one for floats?

+12  A: 

NSNumber is a class, not a primitive, and is used when you need to put raw numbers into dictionaries, arrays, or otherwise encapsulate them. NSInteger, NSUInteger, CGFloat, etc are simple types and correspond (on 32-bt systems like the iPhone) to int, unsigned int and float.

As a general rule, if you need to store a number somewhere, use NSNumber. If you're doing calculations, loops, etc, use NSInteger, NSUInteger or CGFloat.

You can wrap an NSInteger into an NSNumber:

NSNumber *aNumber = [NSNumber numberWithInteger:21];

... and get it back:

NSInteger anInteger = [aNumber integerValue];

You can find out more info here: http://iphonedevelopertips.com/cocoa/nsnumber-and-nsinteger.html

iKenndac
If the number will never be negative, should I use NSUInteger?
Mk12
And which should I use for a number with a decimal?
Mk12
Why is it CGFloat and not NSFloat?
Mk12
If you can absolutely, positively guarantee that you'll never have a negative number, NSUInteger gives you more range. Decimals should be of type `double` (I don't think there's an NS/CGDouble). CGFloat comes from the fact that the typedef is in CoreGraphics. I don't know why!
iKenndac
So why double and not CGFloat, or not float?
Mk12
CGFloat is a typedef for float under 32-bit, and double under 64-bit.
Wevah
This provides a useful overview on why to use double instead of float if you care at all about the accuracy of your numbers: http://stackoverflow.com/questions/61872/use-float-or-decimal-for-accounting-application-dollar-amount
iKenndac
but isn't iPhone 32 bit not 64..
Mk12
I missed the iPhone tag >_<.
Wevah
+2  A: 

NSInteger is just like a traditional int in C. It's a typedef. There are others like NSUInteger, CGFloat, etc. that all are synonyms for primitive types.

NSNumber is useful when you need to stick a number into an NSArray or NSDictionary. The standard practice is to use these collections versus rolling your own; the drawback is that they can only contain Objective-C objects.

NSNumber essentially wraps an int (or float, etc) into an Obj-C object (similar to C#/Java's concept of 'boxing' a primitive type) that can be added to an array:

NSArray * myArray = [[NSArray alloc] init];
[myArray addObject:3]; // invalid, will not compile.
[myArray [NSNumber numberWithInt:3]]; // ok

For performance reasons, if you can, use primitive types (like int, float, int[]). However, sometimes you cannot avoid NSArray/NSNumber, such as when you are reading or writing entries into a .plist file.

Jason
NSInteger, NSUInteger, and CGFloat are typedefs that are safe under 32 or 64 bit.
Abizern
+5  A: 

The existing answers are useful; adding to them:

Yes, NSUInteger gives twice the range among positive integers as NSInteger, but I think another critical reason to choose between the two is simply to distinguish among cases where negative values simply do not make sense.

Example: the return value of NSArray's count method is an NSUInteger, which makes sense since we cannot have an array with a negative number of elements. When the coder knows it's unsigned, he/she has more freedom to perform operations that might be unreliable in the signed case, including bitwise operations such as shifting. This blog post talks more about signed vs unsigned.

My guess about CGFloat vs NSFloat (which doesn't exist): It might be the case that the designers of the NeXTStep-named code elements simply didn't need to specify too many float values, outside of time intervals. So they gave NSTimeInterval, which is a floating-point type, but that is clearly intended for use with time intervals. And, frankly, it's great to have that type because you know it's always meant to be in seconds without having to deal with a struct. When you move into the graphics world (where Core Graphics lives), suddenly floats are all around you, hovering in the air (haha). So it makes sense to introduce a CGFloat there. This paragraph is all "educated speculation."

Also, just to be clear about why you might use NSInteger etc instead of primitive types: Because this way it's easier to write portable code that takes full advantage of the machine architecture. For example, a CGFloat uses 32 bits on some machines and 64 bits on others, depending largely on how much of an efficiency gap there is on those machines for those sizes. In some cases, there's no real speedup for using 32 bits vs 64 bits, so you might as well use 64 bits. If you've declared things as CGFloat's, you suddenly get that extra precision "for free" when you recompile.

And, as iKenndac has pointed out, NSNumber is a wrapper class for all of these (and other primitive or quasi-primitive types like the BOOL) which enables you to include it in your NSArrays and NSDictionarys, archive them more easily, and do other things that NSObjects can do.

Tyler
A really, really niggly point:NSTimeinterval is a double, not a float. I'm aware that double is short for double-precision floating point, but still.Also, I understand CGFloat compiling as a double on 64-bit is great, but NSInteger? I can't think of a situation where that'd be useful. Say in code you're doing some maths that needs 64 bits... you can't use NSInteger if you compile for 32. If you fit into 32, why use 64? Seems odd.
iKenndac
You're right, NSTimeInterval is a double. I think it still counts as a "floating-point type," though. Just with double precision.I also agree that in many many cases a lot of code won't improve by having NSInteger become 64 bits. But here's one possibility: a random number generator. In this case, you really care about speed, so you might want to use 32 bits when that's faster. But if 64 bits works just as well, then you suddenly get a huge boost in random-happiness (_much_ longer cycle length, etc) without much (if any) speed cost.
Tyler