Wann wird NSInteger vs. int verwendet?

344

Wann sollte ich NSIntegervs. int bei der Entwicklung für iOS verwenden? Ich sehe im Apple-Beispielcode, dass sie NSInteger(oder NSUInteger) verwenden, wenn sie einen Wert als Argument an eine Funktion übergeben oder einen Wert von einer Funktion zurückgeben.

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

Aber innerhalb einer Funktion verwenden sie nur, intum einen Wert zu verfolgen

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

int something;
something += somethingElseThatsAnInt;
...

Ich habe gelesen (wurde mir gesagt), dass dies NSIntegereine sichere Möglichkeit ist, eine Ganzzahl in einer 64-Bit- oder 32-Bit-Umgebung zu referenzieren. Warum also intüberhaupt verwenden?

Shizam
quelle

Antworten:

322

Sie möchten normalerweise verwenden, NSIntegerwenn Sie nicht wissen, auf welcher Prozessorarchitektur Ihr Code ausgeführt werden kann. Aus irgendeinem Grund möchten Sie möglicherweise den größtmöglichen Ganzzahltyp, der auf 32-Bit-Systemen nur ein int64-Bit- System ist System ist es ein long.

Ich würde bei der Verwendung NSIntegeranstelle von int/ bleiben, es longsei denn, Sie benötigen sie ausdrücklich.

NSInteger/ NSUIntegersind als * dynamische typedef* s für einen dieser Typen definiert und wie folgt definiert:

#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

Informationen zum richtigen Formatbezeichner, den Sie für jeden dieser Typen verwenden sollten, finden Sie im Abschnitt zum Programmieren von Zeichenfolgen für Plattformabhängigkeiten

Jacob Relkin
quelle
4
Darüber hinaus würde ich sagen, dass es am besten ist, NSInteger zu verwenden, es sei denn, Sie benötigen speziell int oder long int.
v01d
4
@ Shizam Es ist möglich, dass die Verwendung intvon a sogar für a besser geeignet ist long. Vielleicht wissen Sie, dass es einen bestimmten Bereich nicht überschreitet, und denken daher, dass es speichereffizienter ist, es einfach zu verwenden int.
Jacob Relkin
58
Ich bin mit dieser Antwort nicht einverstanden. Das einzige, wofür ich verwenden würde, NSIntegerist die Übergabe von Werten an und von einer API, die dies angibt. Davon abgesehen hat es keinen Vorteil gegenüber einem int oder einem long. Zumindest mit einem int oder einem long wissen Sie, welche Formatspezifizierer in einer printf- oder ähnlichen Anweisung verwendet werden sollen.
JeremyP
3
Was passiert, wenn Sie ein Long speichern müssen und NSInteger verwenden, während Sie in einem 64b-System arbeiten, andere Benutzer jedoch ein 32b-System verwenden? Sie werden den Fehler nicht bemerken, aber der Benutzer wird es tun.
Arielcamus
14
Das ist rückwärts. Verwenden Sie immer int, es sei denn, Sie haben einen bestimmten Grund. Die Verwendung plattformspezifischer Definitionen für einfache Ganzzahlen macht Ihren Code nur schwerer lesbar.
Glenn Maynard
44

Warum intüberhaupt verwenden?

Apple verwendet, intweil für eine Schleifensteuervariable (die nur zur Steuerung der Schleifeniterationen verwendet wird) der intDatentyp in Ordnung ist, sowohl in Bezug auf die Datentypgröße als auch in Bezug auf die Werte, die er für Ihre Schleife enthalten kann. Hier ist kein plattformabhängiger Datentyp erforderlich. Bei einer Regelkreisvariablen reicht intmeistens sogar ein 16-Bit aus.

Apple verwendet NSIntegerfür einen Funktionsrückgabewert oder für ein Funktionsargument, da in diesem Fall der Datentyp [Größe] wichtig ist , weil Sie mit einer Funktion Daten mit anderen Programmen oder mit anderen Codeteilen kommunizieren / übergeben. Siehe die Antwort auf Wann sollte ich NSInteger vs int verwenden? in deiner Frage selbst ...

Sie [Apple] verwenden NSInteger (oder NSUInteger), wenn sie einen Wert als Argument an eine Funktion übergeben oder einen Wert von einer Funktion zurückgeben.

Nur du
quelle
32

OS X ist "LP64". Das bedeutet, dass:

int ist immer 32-Bit.

long long ist immer 64-Bit.

NSIntegerund longsind immer zeigergroß. Das heißt, sie sind 32-Bit auf 32-Bit-Systemen und 64-Bit auf 64-Bit-Systemen.

Der Grund, warum NSInteger vorhanden ist, liegt darin, dass viele ältere APIs fälschlicherweise verwendet wurden, intanstatt longVariablen in Zeigergröße zu speichern , was bedeutete, dass die APIs in ihren 64-Bit-Versionen von intauf geändert werden mussten long. Mit anderen Worten, eine API hat unterschiedliche Funktionssignaturen, je nachdem, ob Sie für 32-Bit- oder 64-Bit-Architekturen kompilieren. NSIntegerbeabsichtigt, dieses Problem mit diesen Legacy-APIs zu maskieren.

Verwenden intSie in Ihrem neuen Code, wenn Sie eine 32-Bit-Variable long longbenötigen , wenn Sie eine 64-Bit-Ganzzahl benötigen longoder NSIntegerwenn Sie eine Variable in Zeigergröße benötigen.

Darren
quelle
25
Die Geschichte ist genau richtig, aber der Rat ist schrecklich. Wenn Sie eine 32-Bit-Variable benötigen, verwenden Sie int32_t. Wenn Sie eine 64-Bit-Ganzzahl benötigen, verwenden Sie int64_t. Wenn Sie eine Variable in Zeigergröße benötigen, verwenden Sie intptr_t.
Stephen Canon
5
Stephen, Ihr Rat ist, dann niemals int, long oder NSInteger zu verwenden?
Darren
7
Nein, mein Rat ist, sie niemals zu verwenden, wenn Sie einen ganzzahligen Typ mit bekannter fester Größe benötigen. Die <stdint.h>Typen existieren zu diesem Zweck.
Stephen Canon
3
Stephen, meine Antwort war die Antwort auf die Frage "Wann sollte NSInteger vs int verwendet werden?" Und nicht "Wie lautet der plattformübergreifende Typname einer 32-Bit-Ganzzahl?". Wenn jemand versucht, sich zwischen NSInteger und int zu entscheiden, weiß er möglicherweise auch, wie groß er auf den von ihm unterstützten Plattformen ist.
Darren
1
Beachten Sie auch, dass LP64dies keine Garantie long longfür 64 Bit ist. Eine LP64Plattform könnte sich long longfür eine 128-Bit-Ganzzahl entscheiden.
Stephen Canon
26

Wenn Sie sich mit der Implementierung von NSInteger befassen:

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

Das NSInteger-Typedef erledigt einfach einen Schritt für Sie: Wenn die Architektur 32-Bit ist, wird es verwendet int, wenn es 64-Bit ist, wird es verwendet long. Mit NSInteger müssen Sie sich keine Gedanken über die Architektur machen, auf der das Programm ausgeführt wird.

Evan Mulawski
quelle
14
Sie müssen sich Sorgen machen, da der richtige Formatbezeichner für NSInteger von der Architektur abhängt.
JeremyP
Der einfachste Weg laut Apple-Handbuch besteht darin, den Wert auf den größten numerischen Typ zu übertragen long long. Daher verwenden alle numerischen Typen denselben Typbezeichner.
Eonil
6
Jetzt ist der einfachste Weg, um zu formatieren, sie einfach zu boxen -NSLog("%@", @(1123));
Eonil
1
Sie können es auch besetzen:NSLog("%li", (long)theNSInteger);
Daniel
Casting macht mich traurig
Tomalbrc
9

Sie sollten NSInteger verwenden, wenn Sie sie mit konstanten Werten wie NSNotFound oder NSIntegerMax vergleichen müssen, da sich diese Werte auf 32-Bit- und 64-Bit-Systemen unterscheiden. Verwenden Sie daher Indexwerte, Anzahl und dergleichen: Verwenden Sie NSInteger oder NSUInteger.

Es tut in den meisten Fällen nicht weh, NSInteger zu verwenden, außer dass es doppelt so viel Speicher beansprucht. Die Auswirkungen auf den Speicher sind sehr gering. Wenn jedoch eine große Anzahl von Zahlen gleichzeitig im Umlauf ist, kann die Verwendung von Ints einen Unterschied machen.

Wenn Sie NSInteger oder NSUInteger verwenden, möchten Sie diese bei Verwendung von Formatzeichenfolgen in lange Ganzzahlen oder vorzeichenlose lange Ganzzahlen umwandeln, da die neue Xcode-Funktion eine Warnung zurückgibt, wenn Sie versuchen, eine NSInteger abzumelden, als ob sie eine bekannte Länge hätte. Sie sollten ebenfalls vorsichtig sein, wenn Sie sie an Variablen oder Argumente senden, die als Ints eingegeben werden, da Sie dabei möglicherweise an Genauigkeit verlieren.

Im Großen und Ganzen ist es einfacher, NSInteger zu verwenden, wenn Sie nicht erwarten, Hunderttausende von ihnen gleichzeitig im Speicher zu haben, als sich ständig um den Unterschied zwischen den beiden zu sorgen.

Asche
quelle
9

Ab sofort (September 2014) würde ich die Verwendung empfehlen NSInteger/CGFloat sofort bei der Interaktion mit iOS-APIs usw. wenn Sie Ihre App auch für arm64 erstellen. Dies liegt daran , dass Sie wahrscheinlich unerwartete Ergebnisse erhalten, wenn Sie verwenden , um die float, longund intTypen.

BEISPIEL: FLOAT / DOUBLE vs CGFLOAT

Als Beispiel nehmen wir die UITableView-Delegatenmethode tableView:heightForRowAtIndexPath:.

In einer 32-Bit-Anwendung funktioniert es einwandfrei, wenn es wie folgt geschrieben ist:

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

floatist ein 32-Bit-Wert und die 44, die Sie zurückgeben, ist ein 32-Bit-Wert. Wenn wir jedoch denselben Code in einer 64-Bit-arm64-Architektur kompilieren / ausführen, ist 44 ein 64-Bit-Wert. Die Rückgabe eines 64-Bit-Werts, wenn ein 32-Bit-Wert erwartet wird, führt zu einer unerwarteten Zeilenhöhe.

Sie können dieses Problem mithilfe des CGFloatTyps lösen

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

Dieser Typ repräsentiert ein 32-Bit floatin einer 32-Bit-Umgebung und ein 64-Bitdouble in einer 64-Bit-Umgebung. Daher erhält die Methode bei Verwendung dieses Typs unabhängig von der Kompilierungs- / Laufzeitumgebung immer den erwarteten Typ.

Gleiches gilt für Methoden, die Ganzzahlen erwarten. Solche Methoden erwarten einen 32-Bit- intWert in einer 32-Bit-Umgebung und einen 64-Bit - Wert longin einer 64-Bit-Umgebung. Sie können diesen Fall lösen, indem Sie den Typ verwenden NSInteger, der als intoder longbasierend auf der Kompilierungs- / Laufzeitumgebung dient.

Leon Lucardie
quelle
Was ist, wenn ich weiß, dass der Wert dieser bestimmten Variablen keine großen Zahlenwerte enthalten kann und ich daher int verwenden möchte? Funktioniert es sowohl in einer 64-Bit-Umgebung? Ich denke, es sollte auch so sein, da ich keine for-Schleife wie diese gesehen habe: for (int i = 0; i <10; i ++) macht ein falsches Verhalten, unabhängig von der Umgebung, in der es ausgeführt wird.
Chanchal Raj
@Chanchal Raj Solange keine Umwandlung oder Konvertierung in andere Typen oder Verwendung / Überschreibung von Klassen und Methoden von Drittanbietern mit dieser Variablen erfolgt, ist die Verwendung eines int anstelle von NSInteger in Ordnung.
Leon Lucardie
9

Unter iOS spielt es derzeit keine Rolle, ob Sie intoder verwenden NSInteger. Es ist wichtiger, wenn iOS auf 64-Bit umstellt.

Einfach ausgedrückt, NSIntegers sind ints in 32-Bit-Code (und damit 32-Bit lang) und longs in 64-Bit-Code ( longs in 64-Bit-Code sind 64-Bit breit, aber 32-Bit in 32-Bit-Code). Der wahrscheinlichste Grund für die Verwendung NSIntegeranstelle von longist, vorhandenen 32-Bit-Code (der ints verwendet) nicht zu beschädigen .

CGFloathat das gleiche Problem: unter 32-Bit (zumindest unter OS X) ist es float; auf 64-Bit ist es double.

Update: Mit der Einführung des iPhone 5s, iPad Air, iPad Mini mit Retina und iOS 7 können Sie jetzt 64-Bit-Code unter iOS erstellen.

Update 2: Die Verwendung von NSIntegers hilft auch bei der Interoperabilität von Swift-Code.

MaddTheSane
quelle
0

int = 4 Byte (fest, unabhängig von der Größe des Architekten) NSInteger = abhängig von der Größe des Architekten (z. B. für 4 Byte Architekt = 4 Byte NSInteger-Größe)

Ankit garg
quelle