Quando utilizzare NSInteger vs. int


344

Quando dovrei usare NSIntegervs. int durante lo sviluppo per iOS? Vedo nel codice di esempio Apple che usano NSInteger(o NSUInteger) quando passano un valore come argomento a una funzione o restituiscono un valore da una funzione.

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

Ma all'interno di una funzione stanno solo usando intper tracciare un valore

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

int something;
something += somethingElseThatsAnInt;
...

Ho letto (mi è stato detto) che NSIntegerè un modo sicuro per fare riferimento a un numero intero in un ambiente a 64 o 32 bit, quindi perché utilizzarlo int?

Risposte:


322

Di solito si desidera utilizzare NSIntegerquando non si conosce il tipo di architettura del processore su cui potrebbe essere eseguito il codice, quindi per qualche motivo si potrebbe desiderare il tipo intero più grande possibile, che sui sistemi a 32 bit è solo un int, mentre su un 64-bit sistema è un long.

Continuerei a usare NSIntegerinvece di int/ a longmeno che tu non lo richieda specificamente.

NSInteger/ NSUIntegersono definiti come * dinamici typedef* per uno di questi tipi e sono definiti in questo modo:

#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

Per quanto riguarda l'identificatore di formato corretto che è necessario utilizzare per ciascuno di questi tipi, consultare la sezione Guida alla programmazione delle stringhe sulle dipendenze della piattaforma


4
Inoltre, direi che è meglio usare NSInteger a meno che non sia necessario int o long int.
v01d

4
@Shizam È possibile che l'uso di un intsia più adatto anche a long. Forse sai che non supererà un certo intervallo e quindi pensi che sarà più efficiente in termini di memoria da usare semplicemente int.
Jacob Relkin,

58
Non sono d'accordo con questa risposta. L'unica cosa che vorrei usare NSIntegerè passare valori da e verso un'API che lo specifica. A parte questo, non ha alcun vantaggio su un int o un long. Almeno con un int o un lungo sai quali identificatori di formato usare in una dichiarazione printf o simile.
JeremyP,

3
Cosa succede se è necessario archiviare a lungo e si utilizza NSInteger mentre si lavora in un sistema 64b ma un altro utente utilizza un sistema 32b? Non noterai l'errore ma l'utente lo farà.
Arielcamus,

14
Questo è al contrario. Usa sempre int a meno che tu non abbia altrimenti un motivo specifico. L'uso di definizioni specifiche della piattaforma per interi semplici non fa altro che rendere più difficile la lettura del codice.
Glenn Maynard,

44

Perché usare intaffatto?

Apple usa intperché per una variabile di controllo del ciclo (che viene utilizzata solo per controllare le iterazioni del ciclo) il inttipo di dati va bene, sia nella dimensione del tipo di dati che nei valori che può contenere per il tuo ciclo. Non è necessario il tipo di dati dipendente dalla piattaforma qui. Per una variabile di controllo di loop, anche un 16 bit intfarà la maggior parte del tempo.

Apple utilizza NSIntegerper un valore restituito da una funzione o per un argomento di funzione perché in questo caso il tipo di dati [size] è importante , perché ciò che si sta facendo con una funzione è comunicare / passare dati con altri programmi o con altri pezzi di codice; vedi la risposta a Quando dovrei usare NSInteger vs int? nella tua stessa domanda ...

[Apple] usano NSInteger (o NSUInteger) quando passano un valore come argomento a una funzione o restituiscono un valore da una funzione.


32

OS X è "LP64". Ciò significa che:

int è sempre a 32 bit.

long long è sempre a 64 bit.

NSIntegere longsono sempre delle dimensioni di un puntatore. Ciò significa che sono a 32 bit su sistemi a 32 bit e 64 bit su sistemi a 64 bit.

Il motivo per cui esiste NSInteger è perché molte API legacy sono state utilizzate in modo errato intanziché longcontenere variabili di dimensioni puntatore, il che significava che le API dovevano cambiare da inta longnelle loro versioni a 64 bit. In altre parole, un'API avrebbe firme di funzioni diverse a seconda che si stia compilando per architetture a 32 o 64 bit. NSIntegerintende mascherare questo problema con queste API legacy.

Nel vostro nuovo codice, l'uso intse avete bisogno di una variabile a 32 bit, long longse avete bisogno di un intero a 64 bit, e longo NSIntegerse avete bisogno di una variabile puntatore dimensioni.


25
La storia è perfetta, ma il consiglio è terribile. Se è necessaria una variabile a 32 bit, utilizzare int32_t. Se è necessario un numero intero a 64 bit, utilizzare int64_t. Se è necessaria una variabile delle dimensioni di un puntatore, utilizzare intptr_t.
Stephen Canon,

5
Stephen, il tuo consiglio è di non usare mai int, long o NSInteger?
Darren,

7
No, il mio consiglio è di non usarli mai se si richiede un tipo intero di dimensioni fisse note. I <stdint.h>tipi esistono a tale scopo.
Stephen Canon,

3
Stephen, la mia risposta è stata in risposta alla domanda "Quando usare NSInteger vs int", non "qual è il nome di tipo multipiattaforma di un numero intero a 32 bit". Se qualcuno sta cercando di decidere tra NSInteger e int, potrebbe anche sapere quanto sono grandi sulle piattaforme che supportano.
Darren,

1
Si noti inoltre che LP64non garantisce che long longsia 64 bit. Una LP64piattaforma potrebbe scegliere di long longessere un numero intero a 128 bit.
Stephen Canon,

26

Se approfondisci l'implementazione di NSInteger:

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

Semplicemente, il typedef NSInteger fa un passo per te: se l'architettura è a 32 bit, usa int, se è a 64 bit, usa long. Usando NSInteger, non devi preoccuparti dell'architettura su cui è in esecuzione il programma.


14
Devi preoccuparti, perché l'identificatore di formato corretto per NSInteger dipende dall'architettura.
JeremyP,

Il modo più semplice secondo il manuale di Apple è quello di trasmettere valore al più grande tipo numerico long long. Quindi tutti i tipi numerici useranno lo stesso identificatore di tipo.
Eonil,

6
Ora il modo più semplice per formattare è semplicemente inscatolarli -NSLog("%@", @(1123));
Eonil,

1
puoi anche lanciarlo:NSLog("%li", (long)theNSInteger);
Daniel

il casting mi rende triste
tomalbrc il

9

Dovresti usare NSInteger se devi confrontarli con valori costanti come NSNotFound o NSIntegerMax, poiché questi valori differiranno sui sistemi a 32 e 64 bit, quindi valori di indice, conteggi e simili: usa NSInteger o NSUInteger.

L'uso di NSInteger non fa male nella maggior parte dei casi, tranne per il fatto che occupa il doppio della memoria. L'impatto sulla memoria è molto piccolo, ma se hai una grande quantità di numeri che fluttuano in qualsiasi momento, potrebbe fare la differenza usare gli ints.

Se si utilizza NSInteger o NSUInteger, è consigliabile eseguirne il cast in numeri interi lunghi o numeri lunghi senza segno quando si utilizzano stringhe di formato, poiché la nuova funzione Xcode restituisce un avviso se si tenta di disconnettersi da un NSInteger come se avesse una lunghezza nota. Allo stesso modo dovresti fare attenzione quando li invii a variabili o argomenti digitati come ints, poiché potresti perdere una certa precisione nel processo.

Nel complesso, se non ti aspetti di averne in memoria centinaia di migliaia contemporaneamente, è più facile usare NSInteger piuttosto che preoccuparti costantemente della differenza tra i due.


9

A partire da oggi (settembre 2014), consiglierei di utilizzare NSInteger/CGFloatquando interagisci con le API di iOS ecc. Se stai anche costruendo la tua app per arm64. Questo perché è probabile ottenere risultati imprevisti quando si utilizzano i float, longe inttipi.

ESEMPIO: FLOAT / DOUBLE vs CGFLOAT

Ad esempio prendiamo il metodo delegato UITableView tableView:heightForRowAtIndexPath:.

In un'applicazione solo a 32 bit funzionerà bene se è scritto in questo modo:

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

floatè un valore a 32 bit e il 44 che stai restituendo è un valore a 32 bit. Tuttavia, se compiliamo / eseguiamo questo stesso pezzo di codice in un'architettura arm64 a 64 bit, il 44 sarà un valore a 64 bit. Restituire un valore a 64 bit quando è previsto un valore a 32 bit darà un'altezza di riga imprevista.

È possibile risolvere questo problema utilizzando il CGFloattipo

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

Questo tipo rappresenta un 32 bit floatin un ambiente a 32 bit e un 64 bit doublein un ambiente a 64 bit. Pertanto, quando si utilizza questo tipo, il metodo riceverà sempre il tipo previsto indipendentemente dall'ambiente di compilazione / runtime.

Lo stesso vale per i metodi che prevedono numeri interi. Tali metodi prevedono un intvalore a 32 bit in un ambiente a 32 bit e un 64 bit longin un ambiente a 64 bit. È possibile risolvere questo caso utilizzando il tipo NSIntegerche funge da into o in longbase all'ambiente di compilazione / runtime.


Che cosa succede se conosco il valore di questa particolare variabile non può contenere valori numerici elevati e quindi desidero utilizzare int. Funzionerà bene sia in un ambiente a 64 bit. Penso che dovrebbe farlo anche perché non ho visto un ciclo for in questo modo: for (int i = 0; i <10; i ++) fare qualsiasi comportamento sbagliato indipendentemente dall'ambiente in cui è stato eseguito.
Chanchal Raj

@Chanchal Raj Finché non ci sarà casting o conversione in altri tipi o utilizzo / override di classi e metodi di terze parti che coinvolgono quella variabile, usare un int anziché NSInteger andrà bene.
Leon Lucardie,

9

Su iOS, al momento non importa se usi into NSInteger. Importerà di più se / quando iOS passerà a 64 bit.

In poche parole, NSIntegers sono ints nel codice a 32 bit (e quindi a 32 bit) e longs nel codice a 64 bit ( longs nel codice a 64 bit sono larghi a 64 bit, ma 32 bit nel codice a 32 bit). Il motivo più probabile per l'utilizzo al NSIntegerposto di longè quello di non rompere il codice a 32 bit esistente (che utilizza ints).

CGFloatha lo stesso problema: su 32 bit (almeno su OS X), è float; a 64 bit, lo è double.

Aggiornamento: con l'introduzione di iPhone 5s, iPad Air, iPad Mini con Retina e iOS 7, ora puoi creare codice a 64 bit su iOS.

Aggiornamento 2: Inoltre, l'utilizzo di NSIntegers aiuta l'interoperabilità del codice Swift.


0

int = 4 byte (risolto indipendentemente dalla dimensione dell'architetto) NSInteger = dipende dalla dimensione dell'architetto (ad es. per 4 byte architetto = 4 byte NSInteger dimensione)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.