Cuándo usar NSInteger vs. int

344

¿Cuándo debería usar NSIntegervs. int cuando desarrolle para iOS? Veo en el código de muestra de Apple que usan NSInteger(o NSUInteger) cuando pasan un valor como argumento a una función o devuelven un valor de una función.

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

Pero dentro de una función solo están usando intpara rastrear un valor

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

int something;
something += somethingElseThatsAnInt;
...

He leído (me han dicho) que NSIntegeres una forma segura de hacer referencia a un número entero en un entorno de 64 bits o de 32 bits, ¿por qué usarlo int?

Shizam
fuente

Respuestas:

322

Por lo general, desea usar NSIntegercuando no sabe en qué tipo de arquitectura de procesador podría ejecutarse su código, por lo que, por alguna razón, puede desear el tipo entero más grande posible, que en sistemas de 32 bits es solo un int, mientras que en un de 64 bits sistema es a long.

Me quedaría con el uso en NSIntegerlugar de int/ a longmenos que los requiera específicamente.

NSInteger/ NSUIntegerse definen como * dinámicos typedef* s para uno de estos tipos, y se definen así:

#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

Con respecto al especificador de formato correcto que debe usar para cada uno de estos tipos, consulte la sección de la Guía de programación de cadenas sobre Dependencias de la plataforma

Jacob Relkin
fuente
44
Además, diría que es mejor usar NSInteger a menos que requiera específicamente int o long int.
v01d
44
@Shizam Es posible que usar un intsea ​​más adecuado incluso para un long. Tal vez sepa que no excederá un cierto rango y, por lo tanto, cree que será más eficiente en cuanto a memoria para usar simplemente int.
Jacob Relkin
58
No estoy de acuerdo con esta respuesta. Lo único que usaría NSIntegerpara pasar valores ay desde una API que lo especifica. Aparte de eso, no tiene ninguna ventaja sobre un int o un largo. Al menos con un int o un largo, usted sabe qué especificadores de formato usar en una declaración printf o similar.
JeremyP
3
¿Qué sucede si necesita almacenar mucho tiempo y usa NSInteger mientras trabaja en un sistema 64b pero otro usuario usa un sistema 32b? No notará la falla, pero el usuario sí.
arielcamus
14
Esto es al revés. Siempre use int a menos que tenga una razón específica de lo contrario. El uso de definiciones específicas de plataforma para enteros simples no hace más que hacer que su código sea más difícil de leer.
Glenn Maynard
44

Por que usar int en absoluto?

Apple usa intporque para una variable de control de bucle (que solo se usa para controlar las iteraciones del bucle) el inttipo de datos está bien, tanto en el tamaño del tipo de datos como en los valores que puede contener para su bucle. No es necesario un tipo de datos dependiente de la plataforma aquí.Para una variable de control de bucle, incluso un bit de 16 bits funcionará la intmayor parte del tiempo.

Apple usa NSIntegerpara un valor de retorno de función o para un argumento de función porque en este caso el tipo de datos [tamaño] importa , porque lo que está haciendo con una función es comunicar / pasar datos con otros programas o con otros códigos; vea la respuesta a ¿ Cuándo debería usar NSInteger vs int? en tu pregunta misma ...

ellos [Apple] usan NSInteger (o NSUInteger) cuando pasan un valor como argumento a una función o devuelven un valor de una función.

Sólo tu
fuente
32

OS X es "LP64". Esto significa que:

int siempre es de 32 bits.

long long siempre es de 64 bits.

NSIntegery longsiempre son del tamaño de un puntero. Eso significa que son de 32 bits en sistemas de 32 bits y de 64 bits en sistemas de 64 bits.

La razón por la que NSInteger existe es porque muchas API heredadas se usaron incorrectamente en intlugar de longcontener variables de tamaño de puntero, lo que significaba que las API tenían que cambiar de inta longen sus versiones de 64 bits. En otras palabras, una API tendría firmas de función diferentes dependiendo de si está compilando para arquitecturas de 32 bits o 64 bits. NSIntegerpretende enmascarar este problema con estas API heredadas.

En su nuevo código, úselo intsi necesita una variable de 32 bits, long longsi necesita un número entero de 64 bits y / longo NSIntegersi necesita una variable de tamaño de puntero.

Darren
fuente
25
La historia es acertada, pero el consejo es terrible. Si necesita un uso variable de 32 bits int32_t. Si necesita un uso entero de 64 bits int64_t. Si necesita una variable de tamaño puntero, use intptr_t.
Stephen Canon
55
Stephen, ¿tu consejo es nunca usar int, long o NSInteger entonces?
Darren
77
No, mi consejo es que nunca los use si necesita un tipo entero de tamaño fijo conocido. Los <stdint.h>tipos existen para ese propósito.
Stephen Canon
3
Stephen, mi respuesta fue en respuesta a la pregunta "Cuándo usar NSInteger vs int", no "cuál es el nombre de tipo multiplataforma de un entero de 32 bits". Si alguien está tratando de decidir entre NSInteger e int, también podría saber qué tan grandes son en las plataformas que admiten.
Darren
1
Tenga en cuenta también que LP64no garantiza que long longsea ​​de 64 bits. Una LP64plataforma podría elegir tener long longun número entero de 128 bits.
Stephen Canon
26

Si profundiza en la implementación de NSInteger:

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

Simplemente, el tipo de definición NSInteger hace un paso por usted: si la arquitectura es de 32 bits, usa int, si es de 64 bits, usa long. Con NSInteger, no necesita preocuparse por la arquitectura en la que se ejecuta el programa.

Evan Mulawski
fuente
14
Debe preocuparse, porque el especificador de formato correcto para NSInteger depende de la arquitectura.
JeremyP
La forma más sencilla de acuerdo con el manual de Apple es convertir el valor al tipo numérico más grande long long. Por lo tanto, todos los tipos numéricos usarán el mismo especificador de tipo.
Eonil
66
Ahora, la forma más sencilla de formatear es encajonarlosNSLog("%@", @(1123));
Eonil
1
también puedes lanzarlo:NSLog("%li", (long)theNSInteger);
Daniel
el casting me pone triste
tomalbrc
9

Debe usar NSIntegers si necesita compararlos con valores constantes como NSNotFound o NSIntegerMax, ya que estos valores diferirán en los sistemas de 32 bits y 64 bits, por lo tanto, valores de índice, recuentos y similares: use NSInteger o NSUInteger.

No hace daño usar NSInteger en la mayoría de las circunstancias, excepto que ocupa el doble de memoria. El impacto en la memoria es muy pequeño, pero si tiene una gran cantidad de números flotando en cualquier momento, puede ser diferente usar ints.

Si usa NSInteger o NSUInteger, querrá convertirlos en enteros largos o enteros largos sin signo cuando use cadenas de formato, ya que la nueva función Xcode devuelve una advertencia si intenta cerrar sesión en un NSInteger como si tuviera una longitud conocida. De manera similar, debe tener cuidado al enviarlos a variables o argumentos que se escriben como ints, ya que puede perder algo de precisión en el proceso.

En general, si no espera tener cientos de miles de ellos en la memoria a la vez, es más fácil usar NSInteger que preocuparse constantemente por la diferencia entre los dos.

Ceniza
fuente
9

A partir de este momento (septiembre de 2014), recomendaría usarlo NSInteger/CGFloatal interactuar con las API de iOS, etc., si también está creando su aplicación para arm64. Esto se debe a que es probable que obtenga resultados inesperados cuando use el float, longyint tipos.

EJEMPLO: FLOTADOR / DOBLE vs CGFLOAT

Como ejemplo tomamos el método delegado UITableView tableView:heightForRowAtIndexPath:.

En una aplicación de solo 32 bits, funcionará bien si se escribe así:

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

floates un valor de 32 bits y el 44 que está devolviendo es un valor de 32 bits. Sin embargo, si compilamos / ejecutamos este mismo código en una arquitectura arm64 de 64 bits, el 44 será un valor de 64 bits. Devolver un valor de 64 bits cuando se espera un valor de 32 bits dará una altura de fila inesperada.

Puede resolver este problema utilizando el CGFloattipo

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

Este tipo representa un floatentorno de 32 bits en un entorno de 32 bits y uno de 64 bits.double en un entorno de 64 bits. Por lo tanto, al usar este tipo, el método siempre recibirá el tipo esperado independientemente del entorno de compilación / tiempo de ejecución.

Lo mismo es cierto para los métodos que esperan enteros. Dichos métodos esperarán un intvalor de 32 bits en un entorno de 32 bits y un valor de 64 bits longen un entorno de 64 bits. Puede resolver este caso utilizando el tipo NSIntegerque sirve como into longbasado en el entorno de compilación / tiempo de ejecución.

Leon Lucardie
fuente
¿Qué sucede si sé que el valor de esta variable en particular no puede contener valores de números grandes y deseo utilizar int, por lo tanto? ¿Funcionará bien tanto en un entorno de 64 bits? Creo que también debería hacerlo, ya que no he visto un bucle for como este: for (int i = 0; i <10; i ++) haciendo un comportamiento incorrecto independientemente del entorno en el que se ejecute.
Chanchal Raj
@Chanchal Raj Mientras no haya conversión o conversión a otros tipos o uso / anulación de clases y métodos de terceros que involucren esa variable, usar un int en lugar de NSInteger estará bien.
Leon Lucardie
9

En iOS, actualmente no importa si usa into NSInteger. Importará más si / cuando iOS se mueve a 64 bits.

En pocas palabras, NSIntegers son ints en código de 32 bits (y, por lo tanto, de 32 bits de longitud) y longs en código de 64 bits ( longs en código de 64 bits tienen 64 bits de ancho, pero 32 bits en código de 32 bits). La razón más probable para usar en NSIntegerlugar de longes no romper el código de 32 bits existente (que usa ints).

CGFloattiene el mismo problema: en 32 bits (al menos en OS X), es float; en 64 bits, es double.

Actualización: con la introducción del iPhone 5s, iPad Air, iPad Mini con Retina e iOS 7, ahora puede crear código de 64 bits en iOS.

Actualización 2: Además, el uso de NSIntegers ayuda con la interoperabilidad del código Swift.

MaddTheSane
fuente
0

int = 4 byte (tamaño fijo independiente del arquitecto) NSInteger = depende del tamaño del arquitecto (p. ej., para 4 byte architect = 4 byte NSInteger size)

Ankit Garg
fuente