web-dev-qa-db-fra.com

Quand utiliser NSInteger vs int

Quand devrais-je utiliser NSInteger vs. int lors du développement pour iOS? Je vois dans l'exemple de code Apple qu'ils utilisent NSInteger (ou NSUInteger) lorsqu'ils transmettent une valeur en tant qu'argument à une fonction ou renvoient une valeur à partir d'une fonction.

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

Mais dans une fonction, ils utilisent juste int pour suivre une valeur

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

int something;
something += somethingElseThatsAnInt;
...

J'ai lu (on m'a dit) que NSInteger est un moyen sûr de référencer un entier dans un environnement 64 bits ou 32 bits, alors pourquoi utiliser int?

337
Shizam

Vous voulez généralement utiliser NSInteger lorsque vous ne connaissez pas l'architecture de processeur sur laquelle votre code peut s'exécuter. Par conséquent, vous pouvez souhaiter le type le plus grand possible, qui sur les systèmes 32 bits n'est qu'un int, alors que sur un système 64 bits, il s’agit d’un long.

Je me contenterais d'utiliser NSInteger au lieu de int/long sauf si vous en avez spécifiquement besoin.

NSInteger/NSUInteger sont définis comme * dynamiques typedef * s selon l'un de ces types, et ils sont définis comme suit:

#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

En ce qui concerne le spécificateur de format correct que vous devez utiliser pour chacun de ces types, consultez la section Guide de programmation des chaînes sur les dépendances de plate-forme

316
Jacob Relkin

Pourquoi utiliser int du tout?

Apple utilise int car, pour une variable de contrôle de boucle (utilisée uniquement pour contrôler les itérations de la boucle), le type de données int convient, à la fois en taille et en valeur qu'il peut contenir pour votre boucle. Pas besoin de type de données dépendant de la plate-forme ici. Pour une variable de contrôle de boucle, même un int 16 bits fera la plupart du temps.

Apple utilise NSInteger pour une valeur de retour de fonction ou pour un argument de fonction car dans ce cas, le type de données [taille] est important, car ce que vous faites avec une fonction est de communiquer/transmettre des données avec d'autres programmes ou avec d'autres éléments de code; voir la réponse à Quand devrais-je utiliser NSInteger vs int? dans votre question elle-même ...

ils [Apple] utilisent NSInteger (ou NSUInteger) lorsqu'ils transmettent une valeur en tant qu'argument d'une fonction ou renvoient un valeur d'une fonction.

44
Only You

OS X est "LP64". Cela signifie que:

int est toujours 32 bits.

long long est toujours 64 bits.

NSInteger et long sont toujours de la taille d'un pointeur. Cela signifie qu’ils sont 32 bits sur les systèmes 32 bits et 64 bits sur les systèmes 64 bits.

NSInteger existe parce que de nombreuses API héritées utilisaient incorrectement int au lieu de long pour contenir des variables de la taille d'un pointeur, ce qui impliquait que les API devaient passer de int à long dans leurs versions 64 bits. En d'autres termes, une API aura différentes signatures de fonction selon que vous compilez pour des architectures 32 bits ou 64 bits. NSInteger a l'intention de masquer ce problème avec ces API héritées.

Dans votre nouveau code, utilisez int si vous avez besoin d’une variable 32 bits, long long si vous avez besoin d’un entier 64 bits et long ou NSInteger si vous avez besoin d’un variable de la taille d'un pointeur.

31
Darren

Si vous creusez dans l'implémentation de NSInteger:

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

Simplement, NSInteger typedef fait un pas pour vous: si l’architecture est 32 bits, il utilise int, si elle est 64 bits, il utilise long. Avec NSInteger, vous n'avez pas à vous soucier de l'architecture sur laquelle le programme est exécuté.

26
Evan Mulawski

Vous devez utiliser NSIntegers si vous devez les comparer à des valeurs constantes telles que NSNotFound ou NSIntegerMax, car ces valeurs différeront sur les systèmes 32 bits et 64 bits. Par conséquent, les valeurs d'index, les nombres et autres: utilisez NSInteger ou NSUInteger.

Il n’est pas inutile d’utiliser NSInteger dans la plupart des cas, sauf que cela prend deux fois plus de mémoire. L'impact sur la mémoire est très faible, mais si vous avez beaucoup de chiffres en même temps, l'utilisation d'Ints peut faire la différence.

Si vous utilisez NSInteger ou NSUInteger, vous voudrez les convertir en entiers longs ou non signés lorsque vous utilisez des chaînes de format, car la nouvelle fonctionnalité Xcode renvoie un avertissement si vous essayez de déconnecter un NSInteger comme si sa longueur était connue. Vous devez également faire attention lorsque vous les envoyez à des variables ou à des arguments qui sont typés en tant qu'ints, car vous pourriez perdre un peu de précision dans le processus.

Dans l’ensemble, si vous ne vous attendez pas à en avoir simultanément des centaines de milliers dans la mémoire, il est plus facile d’utiliser NSInteger que de s’inquiéter constamment de la différence entre les deux.

9
Ash

Sur iOS, peu importe si vous utilisez int ou NSInteger. Ce sera plus important si/quand iOS passe à 64 bits.

Autrement dit, NSIntegers sont ints en code 32 bits (et donc de 32 bits de long) et longs en code 64 bits (longs en code 64 bits sont 64 bits, mais 32 bits en code 32 bits). La raison la plus probable pour utiliser NSInteger au lieu de long est de ne pas rompre le code 32 bits existant (qui utilise ints).

CGFloat a le même problème: sur 32 bits (du moins sur OS X), il s'agit de float; sur 64 bits, c'est double.

Mise à jour: Avec l'introduction de l'iPhone 5s, de l'iPad Air, de l'iPad Mini avec Retina et d'iOS 7, vous pouvez désormais créer du code 64 bits sur iOS.

Mise à jour 2: De plus, l’utilisation de NSIntegers facilite l’interopérabilité du code Swift.

9
MaddTheSane

Pour le moment (septembre 2014), je vous recommanderais d'utiliser NSInteger/CGFloat lors de l'interaction avec les API iOS, etc., si vous construisez également votre application pour arm64. En effet, vous obtiendrez probablement des résultats inattendus lorsque vous utiliserez les types float, long et int.

EXEMPLE: FLOTTEUR/DOUBLE vs CGFLOAT

A titre d'exemple, prenons la méthode de délégué UITableView tableView:heightForRowAtIndexPath:.

Dans une application 32 bits uniquement, cela fonctionnera correctement s'il est écrit comme suit:

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

float est une valeur de 32 bits et le 44 que vous renvoyez est une valeur de 32 bits. Cependant, si nous compilons/exécutons ce même morceau de code dans une architecture arm64 64 bits, la valeur 44 sera une valeur 64 bits. Le renvoi d'une valeur 64 bits lorsqu'une valeur 32 bits est attendue donnera une hauteur de ligne inattendue.

Vous pouvez résoudre ce problème en utilisant le type CGFloat

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

Ce type représente un float 32 bits dans un environnement 32 bits et un double 64 bits dans un environnement 64 bits. Par conséquent, lors de l'utilisation de ce type, la méthode recevra toujours le type attendu, quel que soit l'environnement de compilation/exécution.

Il en va de même pour les méthodes qui attendent des entiers. De telles méthodes attendent une valeur int 32 bits dans un environnement 32 bits et une valeur long 64 bits dans un environnement 64 bits. Vous pouvez résoudre ce problème en utilisant le type NSInteger qui sert de int ou de long en fonction de l’environnement compile/runtime.

9
Leon Lucardie

int = 4 octets (fixe quelle que soit la taille de l'architecte) NSInteger = dépend de la taille de l'architecte (par exemple, pour un architecte à 4 octets = 4 octets de taille NSInteger)

0
Ankit garg