ios - Cuándo usar NSInteger vs. int
objective-c types (8)
A partir de este momento (septiembre de 2014) recomendaría el uso de NSInteger/CGFloat
al interactuar con API de iOS, etc., si también está creando su aplicación para arm64. Esto se debe a que probablemente obtendrá resultados inesperados cuando utilice los tipos float
, long
e int
.
EJEMPLO: FLOTADOR / DOBLE vs CGFLOAT
Como ejemplo tomamos el método delegado 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;
}
float
es un valor de 32 bits y el 44 que está devolviendo es un valor de 32 bits. Sin embargo, si compilamos / ejecutamos este mismo fragmento de 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á un alto de fila inesperado.
Puedes resolver este problema usando el tipo CGFloat
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
Este tipo representa una float
32 bits en un entorno de 32 bits y un double
64 bits 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 números enteros. Tales métodos esperarán un valor int
32 bits en un entorno de 32 bits y un long
64 bits en un entorno de 64 bits. Puede resolver este caso utilizando el tipo NSInteger
que sirve como int
o long
según el entorno de compilación / tiempo de ejecución.
¿Cuándo debo usar NSInteger
vs. int cuando desarrollo para iOS? Veo en el código de ejemplo de Apple que usan NSInteger
(o NSUInteger
) cuando pasan un valor como argumento a una función o devuelven un valor desde una función.
- (NSInteger)someFunc;...
- (void)someFuncWithInt:(NSInteger)value;...
Pero dentro de una función solo están usando int
para rastrear un valor
for (int i; i < something; i++)
...
int something;
something += somethingElseThatsAnInt;
...
He leído (me han dicho) que NSInteger
es una forma segura de hacer referencia a un entero en un entorno de 64 bits o de 32 bits. ¿Por qué usar int
en absoluto?
Debe usar NSIntegers si necesita compararlos con valores constantes como NSNotFound o NSIntegerMax, ya que estos valores diferirán en sistemas de 32 y 64 bits, así que los valores de índice, conteos y similares: use NSInteger o NSUInteger.
No duele usar NSInteger en la mayoría de las circunstancias, excepto que ocupa el doble de memoria. El impacto de la memoria es muy pequeño, pero si tiene una gran cantidad de números flotando en un momento dado, puede hacer una diferencia al usar caracteres.
Si SÍ usa NSInteger o NSUInteger, deseará 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 NSInteger como si tuviera una longitud conocida. Igualmente, debe tener cuidado al enviarlos a variables o argumentos que se escriben como ints, ya que puede perder cierta 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.
En iOS, actualmente no importa si usa int
o NSInteger
. Importa más si / cuando iOS se mueve a 64 bits.
En pocas palabras, NSInteger
s son int
s en código de 32 bits (y por lo tanto de 32 bits de longitud) y s long
en código de 64 bits (s long
en código de 64 bits son de 64 bits de ancho, pero 32 bits en 32- código de bits). La razón más probable para usar NSInteger
lugar de por long
es no romper el código de 32 bits existente (que usa int
s).
CGFloat
tiene 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 y iOS 7, ahora puede crear un código de 64 bits en iOS.
Actualización 2: Además, el uso de NSInteger
ayuda con la interoperabilidad del código Swift.
OS X es "LP64". Esto significa que:
int
es siempre de 32 bits.
long long
es siempre de 64 bits.
NSInteger
y long
siempre son de tamaño puntero. Eso significa que son 32 bits en sistemas de 32 bits y 64 bits en sistemas de 64 bits.
La razón por la que NSInteger existe es porque muchas API heredadas utilizaron incorrectamente int
lugar de long
para contener variables de tamaño de puntero, lo que significaba que las API debían cambiar de int
a long
en 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 de 64 bits. NSInteger
pretende enmascarar este problema con estas API heredadas.
En su nuevo código, use int
si necesita una variable de 32 bits, long long
si necesita un entero de 64 bits y long
o NSInteger
si necesita una variable de tamaño de puntero.
Por lo general, desea usar NSInteger
cuando 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 de int
más grande posible, que en sistemas de 32 bits es solo un int
, mientras que en un 64 sistema de bits es un long
Me quedaría con el uso de NSInteger
lugar de int
/ long
menos que usted lo requiera específicamente.
NSInteger
/ NSUInteger
se definen como * typedef
* s dinámico 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 utilizar para cada uno de estos tipos, consulte la sección Guía de programación de cadenas en Dependencias de plataforma
Si profundizas en la implementación de NSInteger:
#if __LP64__
typedef long NSInteger;
#else
typedef int NSInteger;
#endif
Simplemente, el typedef NSInteger hace un paso por usted: si la arquitectura es de 32 bits, usa int
, si es de 64 bits, usa long
. Al usar NSInteger, no necesita preocuparse por la arquitectura en la que se está ejecutando el programa.
int = 4 byte (tamaño fijo independientemente del arquitecto) NSInteger = depende del tamaño del arquitecto (por ejemplo, para 4 byte architect = 4 byte NSInteger tamaño)
¿Por qué usar int
en absoluto?
Apple usa int
porque para una variable de control de bucle (que solo se usa para controlar las iteraciones del bucle) el tipo de datos int
está bien, tanto en el tamaño del tipo de datos como en los valores que puede contener para su bucle. No es necesario el tipo de datos dependiente de la plataforma aquí. Para una variable de control de bucle, incluso un int
16 bits funcionará la mayor parte del tiempo.
Apple usa NSInteger
para un valor de retorno de función o para un argumento de función porque en este caso el tipo de datos [tamaño] es importante , porque lo que está haciendo con una función es comunicar / pasar datos con otros programas o con otras piezas de código; ver la respuesta a ¿ Cuándo debo usar NSInteger vs int? en tu propia pregunta ...
ellos [Apple] usan NSInteger (o NSUInteger) cuando pasan un valor como argumento a una función o devuelven un valor desde una función.