Comment incrémenter un NSNumber

108

Comment incrémenter un NSNumber?

ie myNSNumber ++

TheLearner
la source
2
N'oubliez pas: lors de l'utilisation NSNumber *, vérifiez toujours si les types primitifs suffiront.
WKS
1
Je suis surpris qu'il n'y ait pas de réponse offrant un moyen rapide / optimisé de le faire, car simplement pour augmenter la valeur, vous devez interroger, combiner et créer un nouvel objet, donc faire cela en boucle peut prendre du temps.
PetrV

Réponses:

123

Mise à jour: FYI, j'aime personnellement mieux les réponses en une ligne de BoltClock et DarkDusts. Ils sont plus concis et ne nécessitent pas de variables supplémentaires.


Pour incrémenter un NSNumber, vous allez devoir obtenir sa valeur, l'incrémenter et le stocker dans un nouveauNSNumber .

Par exemple, pour un NSNumbertenant un entier:

NSNumber *number = [NSNumber numberWithInt:...];
int value = [number intValue];
number = [NSNumber numberWithInt:value + 1];

Ou pour NSNumbertenir un nombre à virgule flottante:

NSNumber *number = [NSNumber numberWithDouble:...];
double value = [number doubleValue];
number = [NSNumber numberWithDouble:value + 1.0];
Itai Ferber
la source
62
C'est la principale raison pour laquelle je déteste les propriétés NSNumber dans Core Data. NSNumber est si peu pratique de travailler avec et d'effectuer des mathématiques.
Christian Schlensker
encore une fois NSNumber pas travaillé lors de l'initialisation avec zéro donne une valeur de garbage.
Jignesh B
désolé, à quoi sert le ...support? C'est une référence de pseudo-code, non? XCode does...
boulder_ruby
@boulder_ruby Le ...est juste un espace réservé pour n'importe quel nombre que vous voulez.
Itai Ferber
126

NSNumberles objets sont immuables; le mieux que vous puissiez faire est de saisir la valeur primitive, de l'incrémenter puis d'envelopper le résultat dans son propre NSNumberobjet:

NSNumber *bNumber = [NSNumber numberWithInt:[aNumber intValue] + 1];
BoltClock
la source
28
Langues modernes: 1, Objective-C: 0.
devios1
77

Pour tous ceux qui utilisent la dernière version de Xcode (en écrivant ceci à partir de 4.4.1, SDK 5.1), avec l'utilisation de littéraux d'objet, vous pouvez nettoyer le code encore un peu plus ...

NSNumber *x = @(1);
x = @([x intValue] + 1);
// x = 2

Encore un peu pénible de gérer la boxe et de tout déballer pour faire des opérations simples, mais ça va mieux, ou du moins plus court.

shortstuffsushi
la source
6
@softRli Consultez clang.llvm.org/docs/ObjectiveCLiterals.html pour voir plus de littéraux ObjC! Imo très pratique.
chown
1
Et d'ailleurs, vous pouvez utiliser x - @ (x.intValue + 1), bien que beaucoup de gens n'aiment pas utiliser la notation par points pour invoquer des méthodes sans propriété. C'est plus court, mais pourrait être appelé abus de la notation par points.
Duncan C
@boulder_ruby, c'est une réaffectation. Les NSNumbers sont immuables, donc pour "incrémenter" la valeur, vous devez en fait la réaffecter à une nouvelle valeur.
shortstuffsushi
30

Les NSNumbers sont immuables, vous devez créer une nouvelle instance.

// Work with 64 bit to support very large values
myNSNumber = [NSNumber numberWithLongLong:[myNSNumber longLongValue] + 1];

// EDIT: With modern syntax:
myNSNumber = @([myNSNumber longLongValue] + 1);
DarkDust
la source
24

Mettez-les tous ensemble, et vous avez:

myNSNumber = @(myNSNumber.intValue + 1);
JLundell
la source
ne réaffectez-vous pas la valeur de myNSNumber ici? Je pensais que ce n'était pas autorisé parce que les NSNumberobjets sont immuables (?)
boulder_ruby
1
Vous créez un nouvel objet NSNumber. myNSNumber est un pointeur (NSNumber *) et a une nouvelle valeur lorsque vous avez terminé.
JLundell
3

J'aime l'expression dot car elle est plus concise et c'est pourquoi IOS la prend en charge en premier lieu:

myNSNumber = [NSNumber numberWithInt:myNSNumber.intValue + 1];
jack
la source
la notation par points ne fait pas ce que vous pensez, et peut être parfois plus lente (elle pourrait être par défaut "valueForKey:" si aucun accesseur synthétisé n'existe pour la "propriété" (dans votre cas intValue). intValue n'a jamais été défini comme @property de NSNumber.
Motti Shneor le
2

Si vous l'utilisez pour stocker une valeur intégrale:

myNSNumber = @(myNSNumber.longLongValue + 1);

Pour les trucs en virgule flottante, la réponse courte est la suivante, mais c'est une mauvaise idée de le faire, vous perdrez de la précision et si vous faites une sorte de comparaison plus tard comme [myNSNumber isEqual: @ (4.5)] vous pourriez être surpris :

myNSNumber = @(myNSNumber.floatValue + 1);

Si vous avez besoin de faire des maths sur des nombres à virgule flottante représentés comme des objets en Objective-C (c'est-à-dire si vous devez les mettre dans des tableaux, des dictionnaires, etc.), vous devriez utiliser NSDecimalNumber.

lms
la source
Si vous refusez de voter, autant être constructif et dire pourquoi.
lms le
Votre réponse implique que c'est NSNumber qui introduit des problèmes d'arrondi. Ce n'est pas correct, NSNumber a le même comportement d'arrondi que les types scalaires. Aussi votre conseil d'utiliser NSDecimalNumbers est assez irritant. Là, vous sous-entendez que ceux-ci sont nécessaires si vous avez besoin des premiers objets citoyens dans onmbjective-c. Mais bien sûr, nsnumbers aux objets aussi. NSDecimalNumbers ont une précision plus élevée, mais une erreur d'arrondi peut également se produire avec eux. Et: op pose des questions sur l'incrémentation, votre réponse avec float et double arithmétique. Mais ceux-ci n'ont aucun incrément, car ils n'ont pas de successeur naturel.
vikingosegundo
@vikingosegundo C'est la conversion d'un NSNumber en float qui provoque la perte de précision car NSNumber stocke les nombres de manière abstraite où float est base2, donc ce n'est pas la faute du NSNumber, mais celle de la conversion dans les deux sens. Et NSDecimalNumbers ne causera pas d' erreurs d'arrondi pour l'arithmétique base10, et ils sont conçus pour l'arithmétique, lisez la doc. L'OP a posé des questions sur l'incrémentation d'un NSNumber, et je lui ai donné une réponse correcte et lisible pour le cas intégral, et a également donné une réponse pour le cas à virgule flottante, mais je l'ai déconseillé et j'ai ensuite fait une meilleure suggestion.
lms
Une instance peut représenter n'importe quel nombre qui peut être exprimé sous la forme d'une mantisse x 10 exposant où la mantisse est un entier décimal jusqu'à 38 chiffres de long, et l'exposant est un entier compris entre -128 et 127. Tous les nombres ne peuvent pas être exprimés ainsi. OP a également demandé une incrémentation facile. NSDecimalNumber ne fournit pas cela. et votre réponse implique toujours que vous avez besoin de NSDecimalNumbers dans l'espace objet. C'est faux.
vikingosegundo
Mec, j'essayais d'être vraiment utile avec ma réponse, et j'ai pensé que le vote négatif était dû au fait que je me suis trompé et que je pensais que je pourrais apprendre quelque chose de nouveau. Je peux voir maintenant que ce n'est pas le cas. Vos commentaires n'ont aucun sens et je suggère que vous ayez une lecture sur les systèmes numériques parce qu'un système numérique de base 10. (Re. Votre citation) ne causera aucune erreur d'arrondi pour les nombres de base 10, je n'ai rien dit sur la précision, juste la précision, mais 128 décimales ont aussi beaucoup de précision.
lms
0

Utilisez une catégorie pour faciliter l'utilisation future. Voici une idée de base.

 - (void)incrementIntBy:(int)ammount {
      self = [NSNumber numberWithInt:(self.intValue + ammount)];
 }
nizx
la source
Pouah. Une catégorie qui implémente une méthode d'instance qui remplace self?!? C'est vraiment méchant. Pourquoi ne pas écrire une méthode d'instance qui a un retour non void du NSNumber résultant.
Duncan C
NSNumber est défini comme immuable, par conséquent, cette méthode de catégorie viole son immuabilité supposée (même si elle remplace self). Une telle catégorie mieux conçue ajouterait à la place un nouvel initialiseur à NSNumber, sous la forme: + numberByIncrementingAmounf: (int) amount;
Motti Shneor le
0

Beaucoup de bonnes informations dans les réponses à cette question. J'ai utilisé la réponse sélectionnée dans mon code et cela a fonctionné. Ensuite, j'ai commencé à lire le reste des articles et j'ai beaucoup simplifié le code. C'est un peu plus difficile à lire si vous n'êtes pas familier avec les changements de notation introduits dans Xcode 5, mais c'est beaucoup plus propre. Je pourrais probablement en faire juste une ligne, mais c'est un peu trop difficile de comprendre ce que je fais.

Je stocke un NSNumber dans un dictionnaire et je souhaite l'incrémenter. Je l'obtiens, le convertis en un entier, l'incrémente en le convertissant en NSNumber, puis le remets dans le dictionnaire.

Ancien code

 NSNumber *correct = [scoringDictionary objectForKey:@"correct"];
 int correctValue = [correct intValue];
 correct = [NSNumber numberWithInt:correctValue + 1];
 [scoringDictionary removeObjectForKey:@"correct"];
 scoringDictionary[@"correct"] = correct;

Nouveau code

NSNumber *correct = [scoringDictionary objectForKey:@"correct"];
scoringDictionary[@"correct"] = @(correct.intValue + 1);
JScarry
la source