When to use NSInteger vs. int
Asked Answered
A

8

350

When should I be using NSInteger vs. int when developing for iOS? I see in the Apple sample code they use NSInteger (or NSUInteger) when passing a value as an argument to a function or returning a value from a function.

- (NSInteger)someFunc;...
- (void)someFuncWithInt:(NSInteger)value;...

But within a function they're just using int to track a value

for (int i; i < something; i++)
...

int something;
something += somethingElseThatsAnInt;
...

I've read (been told) that NSInteger is a safe way to reference an integer in either a 64-bit or 32-bit environment so why use int at all?

Atherosclerosis answered 14/12, 2010 at 23:3 Comment(0)
H
326

You usually want to use NSInteger when you don't know what kind of processor architecture your code might run on, so you may for some reason want the largest possible integer type, which on 32 bit systems is just an int, while on a 64-bit system it's a long.

I'd stick with using NSInteger instead of int/long unless you specifically require them.

NSInteger/NSUInteger are defined as *dynamic typedef*s to one of these types, and they are defined like this:

#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

With regard to the correct format specifier you should use for each of these types, see the String Programming Guide's section on Platform Dependencies

Hathor answered 14/12, 2010 at 23:6 Comment(11)
Additionally, I would say it is best to use NSInteger unless you specifically require int or long int.Roath
So the apple sample code using both makes no sense as its effectively getting none of the benefits of NSInteger?Atherosclerosis
@Atherosclerosis in that specific case, I'd say that using int is perfectly fine because you know what the upper bound is. (something) - If you didn't know what it was, then it'd make more sense to use NSInteger.Hathor
@Atherosclerosis Also, returning an NSInteger is usually best because that number can vary by a lot.Hathor
@Jacob Relkin So there are two reasons to use NSInteger, it solves 32/64 bit systems AND it doubles as a 'long' instead of an 'int'? I guess my point is, if NSInteger is so great why would you ever use int besides its easier to type?Atherosclerosis
@Atherosclerosis It's possible that using an int would be better suited to even a long. Maybe you know that it wont exceed a certain range, and therefore think it will be more memory-efficient to simply use int.Hathor
Ah yes memory, always comes back to that. Ok, I think I got a good decision matrix now on when to use NSInteger vs int.Atherosclerosis
@Shizam: The best reason for using an int is because you're working with an API that uses ints. Very little outside of Cocoa uses NSInteger, so if you're working with another library, it will want to talk in ints rather than NSIntegers.Greta
I disagree with this answer. The only thing I would use NSInteger for is passing values to and from an API that specifies it. Other than that it has no advantage over an int or a long. At least with an int or a long you know what format specifiers to use in a printf or similar statement.Oogenesis
What happens if you need to store a long and you use NSInteger while you are working in a 64b system but other user uses a 32b system? You won't notice the failure but the user will.Whitten
This is backwards. Always use int unless you have a specific reason otherwise. Using platform-specific defines for simple integers does nothing but make your code harder to read.Similitude
P
45

Why use int at all?

Apple uses int because for a loop control variable (which is only used to control the loop iterations) int datatype is fine, both in datatype size and in the values it can hold for your loop. No need for platform dependent datatype here. For a loop control variable even a 16-bit int will do most of the time.

Apple uses NSInteger for a function return value or for a function argument because in this case datatype [size] matters, because what you are doing with a function is communicating/passing data with other programs or with other pieces of code; see the answer to When should I be using NSInteger vs int? in your question itself...

they [Apple] use NSInteger (or NSUInteger) when passing a value as an argument to a function or returning a value from a function.

Pellmell answered 16/3, 2011 at 2:22 Comment(0)
D
33

OS X is "LP64". This means that:

int is always 32-bits.

long long is always 64-bits.

NSInteger and long are always pointer-sized. That means they're 32-bits on 32-bit systems, and 64 bits on 64-bit systems.

The reason NSInteger exists is because many legacy APIs incorrectly used int instead of long to hold pointer-sized variables, which meant that the APIs had to change from int to long in their 64-bit versions. In other words, an API would have different function signatures depending on whether you're compiling for 32-bit or 64-bit architectures. NSInteger intends to mask this problem with these legacy APIs.

In your new code, use int if you need a 32-bit variable, long long if you need a 64-bit integer, and long or NSInteger if you need a pointer-sized variable.

Dippy answered 14/12, 2010 at 23:50 Comment(6)
The history is spot on, but the advice is terrible. If you need a 32-bit variable use int32_t. If you need a 64-bit integer use int64_t. If you need a pointer-sized variable use intptr_t.Dacy
Stephen, your advice is to never use int, long, or NSInteger then?Dippy
No, my advice is to never use them if you require an integer type of known fixed-size. The <stdint.h> types exist for that purpose.Dacy
Stephen, my answer was in response to the question "When to use NSInteger vs int", not "what's the cross-platform typename of a 32-bit integer". If someone's trying to decide between NSInteger and int they might as well know how big they are on the platforms they support.Dippy
Note also that LP64 does not guarantee that long long is 64 bits. An LP64 platform could elect to have long long be a 128 bit integer.Dacy
is this answer still valid for Lion?Philosophy
V
26

If you dig into NSInteger's implementation:

#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif

Simply, the NSInteger typedef does a step for you: if the architecture is 32-bit, it uses int, if it is 64-bit, it uses long. Using NSInteger, you don't need to worry about the architecture that the program is running on.

Vivi answered 14/12, 2010 at 23:10 Comment(5)
You do need to worry, because the correct format specifier for NSInteger is dependent on the architecture.Oogenesis
The simplest way according to Apple manual is casting value to the biggest numeric type long long. So all numeric types will use same type specifier.Prostatectomy
Now the simplest way to format is just boxing them - NSLog("%@", @(1123));Prostatectomy
you can also cast it: NSLog("%li", (long)theNSInteger);Duque
casting makes me sadKaliski
V
11

You should use NSIntegers if you need to compare them against constant values such as NSNotFound or NSIntegerMax, as these values will differ on 32-bit and 64-bit systems, so index values, counts and the like: use NSInteger or NSUInteger.

It doesn't hurt to use NSInteger in most circumstances, excepting that it takes up twice as much memory. The memory impact is very small, but if you have a huge amount of numbers floating around at any one time, it might make a difference to use ints.

If you DO use NSInteger or NSUInteger, you will want to cast them into long integers or unsigned long integers when using format strings, as new Xcode feature returns a warning if you try and log out an NSInteger as if it had a known length. You should similarly be careful when sending them to variables or arguments that are typed as ints, since you may lose some precision in the process.

On the whole, if you're not expecting to have hundreds of thousands of them in memory at once, it's easier to use NSInteger than constantly worry about the difference between the two.

Veda answered 14/3, 2014 at 13:0 Comment(0)
F
10

On iOS, it currently does not matter if you use int or NSInteger. It will matter more if/when iOS moves to 64-bits.

Simply put, NSIntegers are ints in 32-bit code (and thus 32-bit long) and longs on 64-bit code (longs in 64-bit code are 64-bit wide, but 32-bit in 32-bit code). The most likely reason for using NSInteger instead of long is to not break existing 32-bit code (which uses ints).

CGFloat has the same issue: on 32-bit (at least on OS X), it's float; on 64-bit, it's double.

Update: With the introduction of the iPhone 5s, iPad Air, iPad Mini with Retina, and iOS 7, you can now build 64-bit code on iOS.

Update 2: Also, using NSIntegers helps with Swift code interoperability.

Folacin answered 14/1, 2013 at 2:15 Comment(0)
M
9

As of currently (September 2014) I would recommend using NSInteger/CGFloat when interacting with iOS API's etc if you are also building your app for arm64. This is because you will likely get unexpected results when you use the float, long and int types.

EXAMPLE: FLOAT/DOUBLE vs CGFLOAT

As an example we take the UITableView delegate method tableView:heightForRowAtIndexPath:.

In a 32-bit only application it will work fine if it is written like this:

-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 44;
}

float is a 32-bit value and the 44 you are returning is a 32-bit value. However, if we compile/run this same piece of code in a 64-bit arm64 architecture the 44 will be a 64-bit value. Returning a 64-bit value when a 32-bit value is expected will give an unexpected row height.

You can solve this issue by using the CGFloat type

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 44;
}

This type represents a 32-bit float in a 32-bit environment and a 64-bit double in a 64-bit environment. Therefore when using this type the method will always receive the expected type regardless of compile/runtime environment.

The same is true for methods that expect integers. Such methods will expect a 32-bit int value in a 32-bit environment and a 64-bit long in a 64-bit environment. You can solve this case by using the type NSInteger which serves as an int or a long based on the compile/runtime environemnt.

Majordomo answered 5/9, 2014 at 16:54 Comment(2)
What if I know this particular variable's value cannot contain large number values and I wish to use int, therefore. Will it work fine both in a 64-bit environment. I think it should too, as I haven't seen a for loop like this: for (int i=0;i<10;i++) doing any wrong behaviour regardless of environment it is run in.Henebry
@Chanchal Raj As long as there is no casting or conversion to other types or usage/overriding of third-party classes and methods involving that variable, using a int instead of NSInteger will be fine.Majordomo
R
0

int = 4 byte (fixed irrespective size of the architect) NSInteger = depend upon size of the architect(e.g. for 4 byte architect = 4 byte NSInteger size)

Rattler answered 17/1, 2017 at 9:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.