So erhöhen Sie eine NSNumber

108

Wie erhöhe ich eine NSNumber?

dh myNSNumber ++

Der Lernende
quelle
2
Denken Sie daran: NSNumber *Überprüfen Sie bei der Verwendung immer, ob die primitiven Typen ausreichen.
WKS
1
Ich bin überrascht, dass es keine Antwort gibt, die eine schnelle / optimierte Möglichkeit bietet, denn nur um den Wert zu erhöhen, müssen Sie neue Objekte abfragen, kombinieren und erstellen. Daher kann dies zeitaufwändig werden.
PetrV

Antworten:

123

Update: Zu Ihrer Information, ich persönlich mag die einzeiligen Antworten von BoltClock und DarkDusts besser. Sie sind prägnanter und erfordern keine zusätzlichen Variablen.


Um ein zu erhöhen NSNumber, müssen Sie seinen Wert abrufen, diesen erhöhen und in einem neuen speichern NSNumber.

Zum Beispiel für das NSNumberHalten einer Ganzzahl:

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

Oder für das NSNumberHalten einer Gleitkommazahl:

NSNumber *number = [NSNumber numberWithDouble:...];
double value = [number doubleValue];
number = [NSNumber numberWithDouble:value + 1.0];
Itai Ferber
quelle
62
Dies ist der Hauptgrund, warum ich NSNumber-Eigenschaften in Core Data hasse. NSNumber ist so unpraktisch, mit Mathe zu arbeiten und daran zu arbeiten.
Christian Schlensker
Wiederum hat NSNumber beim Initialisieren mit Null nicht funktioniert. Geben Sie den Garbage-Wert an.
Jignesh B
Entschuldigung, wofür steht das ...? Das ist eine Pseudocode-Referenz, oder? XCode nicht...
boulder_ruby
@boulder_ruby Das ...ist nur ein Platzhalter für eine beliebige Nummer.
Itai Ferber
126

NSNumberObjekte sind unveränderlich; das Beste was Sie tun können , ist den Grundwert zu packen, erhöhen sie dann das Ergebnis in seinem eigenen wickeln NSNumberObjekt:

NSNumber *bNumber = [NSNumber numberWithInt:[aNumber intValue] + 1];
BoltClock
quelle
28
Moderne Sprachen: 1, Ziel-C: 0.
devios1
77

Für alle, die die neueste Version von Xcode verwenden (Schreiben ab 4.4.1, SDK 5.1), können Sie mithilfe von Objektliteralen den Code noch ein bisschen mehr bereinigen ...

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

Es ist immer noch eine Qual, mit dem Boxen und Auspacken umzugehen, um einfache Operationen durchzuführen, aber es wird besser oder zumindest kürzer.

Shortstuffsushi
quelle
6
@softRli Weitere Informationen zu ObjC Literals finden Sie unter clang.llvm.org/docs/ObjectiveCLiterals.html ! Sehr praktisch imo.
Chown
1
Außerdem können Sie x - @ (x.intValue + 1) verwenden, obwohl viele Leute die Punktnotation nicht gerne zum Aufrufen von Nicht-Eigenschaftsmethoden verwenden. Es ist kürzer, könnte aber als Missbrauch der Punktnotation bezeichnet werden.
Duncan C
@ boulder_ruby, es ist eine Neuzuweisung. NS-Nummern sind unveränderlich. Um den Wert zu "erhöhen", müssen Sie ihn tatsächlich einem neuen Wert zuweisen.
Shortstuffsushi
30

NSNummern sind unveränderlich, Sie müssen eine neue Instanz erstellen.

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

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

Setzen Sie sie alle zusammen, und Sie haben:

myNSNumber = @(myNSNumber.intValue + 1);
JLundell
quelle
Weisen Sie hier nicht den Wert von myNSNumber neu zu? Ich dachte, das wäre nicht erlaubt, weil NSNumberObjekte unveränderlich sind (?)
boulder_ruby
1
Sie erstellen ein neues NSNumber-Objekt. myNSNumber ist ein Zeiger (NSNumber *) und hat einen neuen Wert, wenn Sie fertig sind.
JLundell
3

Ich mag den Punktausdruck, weil er prägnanter ist und deshalb von IOS in erster Linie unterstützt wird:

myNSNumber = [NSNumber numberWithInt:myNSNumber.intValue + 1];
Jack
quelle
Die Punktnotation macht nicht das, was Sie denken, und kann manchmal langsamer sein (standardmäßig "valueForKey:", wenn für die "Eigenschaft" kein synthetisierter Accessor vorhanden ist (in Ihrem Fall intValue). intValue wurde nie als @property definiert von NSNumber.
Motti Shneor
2

Wenn Sie damit einen ganzzahligen Wert speichern:

myNSNumber = @(myNSNumber.longLongValue + 1);

Für Gleitkomma-Inhalte lautet die kurze Antwort wie folgt, aber es ist eine schlechte Idee, dies zu tun. Sie verlieren an Präzision und wenn Sie später einen Vergleich wie [myNSNumber isEqual: @ (4.5)] durchführen, werden Sie möglicherweise überrascht sein ::

myNSNumber = @(myNSNumber.floatValue + 1);

Wenn Sie Gleitkommazahlen berechnen müssen, die in Objective-C als Objekte dargestellt werden (dh wenn Sie sie in Arrays, Wörterbüchern usw. ablegen müssen), sollten Sie diese verwenden NSDecimalNumber.

lms
quelle
Wenn Sie abstimmen wollen, können Sie genauso gut konstruktiv sein und sagen, warum.
lms
Ihre Antwort impliziert, dass es NSNumber ist, die Rundungsprobleme einführt. Das ist nicht richtig, NSNumber hat das gleiche Rundungsverhalten wie Skalartypen. Auch Ihr Rat zur Verwendung von NSDecimalNumbers ist ziemlich irritierend. Dort implizieren Sie, dass diese notwendig sind, wenn Sie First-Citizen-Objekte in onmbjective-c benötigen. Aber natürlich auch bei Objekten. NSDecimalNumbers haben eine höhere Genauigkeit, es können jedoch auch Rundungsfehler auftreten. Und: op fragt nach Inkrementierung, Ihrer Antwort mit Float und Doppelarithmetik. Aber diese haben kein Inkrement, da sie keinen natürlichen Nachfolger haben.
Vikingosegundo
@vikingosegundo Es konvertiert eine NSNumber in einen Float, was den Genauigkeitsverlust verursacht, da NSNumber Zahlen abstrakt speichert, in denen float base2 ist. Es ist also nicht die Schuld der NSNumber, sondern die der Konvertierung hin und her. Und NSDecimalNumbers verursachen keine Rundungsfehler für die Base10-Arithmetik, und sie sind für die Arithmetik ausgelegt. Lesen Sie das Dokument. Das OP fragte nach einer Erhöhung einer NS-Nummer, und ich gab ihm eine korrekte und lesbare Antwort für den Integralfall und gab auch eine Antwort für den Gleitkommafall, riet jedoch davon ab und folgte dann mit einem besseren Vorschlag.
lms
Eine Instanz kann eine beliebige Zahl darstellen, die als Mantisse x 10 Exponent ausgedrückt werden kann, wobei Mantisse eine bis zu 38 Stellen lange Dezimalzahl und Exponent eine Ganzzahl zwischen -128 und 127 ist. Nicht jede Zahl kann so ausgedrückt werden. Auch OP bat um einfaches Inkrementieren. NSDecimalNumber hat das nicht angegeben. und dennoch impliziert Ihre Antwort, dass Sie NSDecimalNumbers im Objektraum benötigen. das ist falsch.
Vikingosegundo
Alter, ich habe versucht, bei meiner Antwort wirklich hilfreich zu sein, und dachte, die Ablehnung sei darauf zurückzuführen, dass ich etwas falsch gemacht habe und dachte, ich könnte etwas Neues lernen. Ich kann jetzt sehen, dass das nicht der Fall ist. Ihre Kommentare machen keinen Sinn und ich schlage vor, Sie haben eine Lektüre über Zahlensysteme, weil eine Basis 10 Zahlensysteme. (Bezüglich Ihres Zitats) verursacht keine Rundungsfehler für Zahlen der Basis 10, ich sagte nichts über Präzision, nur Genauigkeit, aber 128 Dezimalstellen haben auch viel Präzision.
lms
0

Verwenden Sie eine Kategorie, um die zukünftige Verwendung zu vereinfachen. Hier ist eine Grundidee.

 - (void)incrementIntBy:(int)ammount {
      self = [NSNumber numberWithInt:(self.intValue + ammount)];
 }
nizx
quelle
Pfui. Eine Kategorie, die eine Instanzmethode implementiert, die self ersetzt?!? Das ist ernsthaft böse. Warum nicht eine Instanzmethode schreiben, bei der die resultierende NSNumber nicht ungültig zurückgegeben wird?
Duncan C
NSNumber wird als unveränderlich definiert, daher verletzt diese Kategoriemethode ihre angebliche Unveränderlichkeit (selbst wenn sie sich selbst ersetzt). Eine besser gestaltete solche Kategorie würde stattdessen NSNumber einen neuen Initialisierer in der folgenden Form hinzufügen: + numberByIncrementingAmounf: (int) amount;
Motti Shneor
0

Viele gute Infos in den Antworten auf diese Frage. Ich habe die ausgewählte Antwort in meinem Code verwendet und es hat funktioniert. Dann fing ich an, den Rest der Beiträge zu lesen und vereinfachte den Code sehr. Es ist etwas schwieriger zu lesen, wenn Sie nicht mit den Änderungen in der Notation vertraut sind, die in Xcode 5 eingeführt wurden, aber es ist viel sauberer. Ich könnte es wahrscheinlich nur eine Zeile machen, aber dann ist es ein bisschen zu schwer herauszufinden, was ich tue.

Ich speichere eine NS-Nummer in einem Wörterbuch und möchte sie erhöhen. Ich bekomme es, konvertiere es in ein int, erhöhe es, während ich es in eine NSNumber konvertiere, und setze es dann wieder in das Wörterbuch ein.

Alter Code

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

Neuer Code

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