Come incrementare un NSNumber


108

Come si incrementa un NSNumber?

cioè myNSNumber ++


2
Ricorda: quando usi NSNumber *, controlla sempre se i tipi primitivi saranno sufficienti.
WKS

1
Sono sorpreso che non ci sia risposta che fornisca un modo rapido / ottimizzato per farlo, perché solo per aumentare il valore è necessario interrogare, combinare e creare un nuovo oggetto, quindi farlo in loop può richiedere molto tempo.
PetrV

Risposte:


123

Aggiornamento: Cordiali saluti, personalmente mi piacciono di più le risposte di una riga di BoltClock e DarkDusts. Sono più concisi e non richiedono variabili aggiuntive.


Per incrementare un NSNumber, dovrai ottenere il suo valore, incrementarlo e memorizzarlo in un nuovo NSNumber.

Ad esempio, per NSNumbertenere un numero intero:

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

O per un NSNumbernumero in virgola mobile:

NSNumber *number = [NSNumber numberWithDouble:...];
double value = [number doubleValue];
number = [NSNumber numberWithDouble:value + 1.0];

62
Questo è il motivo numero uno per cui odio le proprietà NSNumber in Core Data. NSNumber è così scomodo con cui lavorare ed eseguire calcoli matematici.
Christian Schlensker

di nuovo NSNumber non ha funzionato durante l'inizializzazione con zero da valore garbage.
Jignesh B

scusa, cosa significa ...? Questo è un riferimento pseudo-codice, giusto? XCode no...
boulder_ruby

@boulder_ruby ...è solo un segnaposto per qualsiasi numero tu voglia.
Itai Ferber

126

NSNumbergli oggetti sono immutabili; il meglio che puoi fare è prendere il valore primitivo, incrementarlo e quindi racchiudere il risultato nel suo NSNumberoggetto:

NSNumber *bNumber = [NSNumber numberWithInt:[aNumber intValue] + 1];

28
Lingue moderne: 1, Objective-C: 0.
devios1

77

Per chiunque stia utilizzando l'ultima versione di Xcode (scrivendo questa a partire dalla 4.4.1, SDK 5.1), con l'uso di letterali oggetto, è possibile ripulire il codice anche un po 'di più ...

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

È ancora un po 'un dolore affrontare la boxe e unboxing di tutto per fare semplici operazioni, ma sta migliorando, o almeno più breve.


6
@softRli Dai un'occhiata a clang.llvm.org/docs/ObjectiveCLiterals.html per vedere più letterali ObjC! Imo molto utile.
chown

1
E del resto potresti usare x - @ (x.intValue + 1), anche se a molte persone non piace usare la notazione a punti per invocare metodi non di proprietà. È più breve, ma potrebbe essere definito un abuso della notazione del punto.
Duncan C

@boulder_ruby, è una riassegnazione. NSNumbers non è modificabile, quindi per "incrementare" il valore, in realtà è necessario riassegnarlo a un nuovo valore.
shortstuffsushi

30

I numeri NS sono immutabili, devi creare una nuova istanza.

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

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

24

Mettili tutti insieme e avrai:

myNSNumber = @(myNSNumber.intValue + 1);

non stai riassegnando il valore di myNSNumber qui? Pensavo che non fosse consentito perché gli NSNumberoggetti sono immutabili (?)
boulder_ruby

1
Stai creando un nuovo oggetto NSNumber. myNSNumber è un puntatore (NSNumber *) e ha un nuovo valore quando hai finito.
JLundell

3

Mi piace l'espressione del punto perché è più concisa ed è per questo che IOS la supporta in primo luogo:

myNSNumber = [NSNumber numberWithInt:myNSNumber.intValue + 1];

la notazione punto non sta facendo quello che pensi e potrebbe essere più lenta a volte (potrebbe essere impostata su "valueForKey:" se non esiste alcuna funzione di accesso sintetizzata per la "proprietà" (nel tuo caso intValue). intValue non è mai stato definito come @property di NSNumber.
Motti Shneor

2

Se lo stai usando per memorizzare un valore integrale:

myNSNumber = @(myNSNumber.longLongValue + 1);

Per le cose in virgola mobile la risposta breve è la seguente, ma è una cattiva idea farlo, perderai la precisione e se farai qualche tipo di confronto in seguito come [myNSNumber isEqual: @ (4.5)] potresti essere sorpreso :

myNSNumber = @(myNSNumber.floatValue + 1);

Se hai bisogno di fare calcoli su numeri in virgola mobile rappresentati come oggetti in Objective-C (cioè se hai bisogno di metterli in array, dizionari, ecc.) Dovresti usare NSDecimalNumber.


Se hai intenzione di esprimere un voto negativo, potresti anche essere costruttivo e dire perché.
lms

La tua risposta implica che è NSNumber che introduce problemi di arrotondamento. Non è corretto, NSNumber ha lo stesso comportamento di arrotondamento dei tipi scalari. Anche il tuo consiglio di usare NSDecimalNumbers è piuttosto irritante. Lì implichi che quelli sono necessari se hai bisogno di oggetti del primo cittadino in un obiettivo-c. Ma ovviamente nnumeri anche sugli oggetti. NSDecimalNumbers ha una precisione maggiore, ma potrebbe verificarsi anche un errore di arrotondamento. E: op chiede dell'incremento, la tua risposta con float e doppia aritmetica. Ma quelli non hanno incremento, poiché non hanno successori naturali.
vikingosegundo

@vikingosegundo Sta convertendo un NSNumber in un float che causa la perdita di accuratezza perché NSNumber memorizza i numeri in modo astratto dove float è base2, quindi non è colpa di NSNumber, ma quella della conversione avanti e indietro. E NSDecimalNumbers non causerà errori di arrotondamento per l'aritmetica in base10 e sono progettati per l'aritmetica, leggi il documento. L'OP ha chiesto di incrementare un NSNumber, e io gli ho dato una risposta corretta e leggibile per il caso integrale, e ho anche dato una risposta per il caso in virgola mobile ma sconsigliato e poi seguito con un suggerimento migliore.
lms

Un'istanza può rappresentare qualsiasi numero che può essere espresso come mantissa x 10 esponente dove mantissa è un numero intero decimale lungo fino a 38 cifre e l'esponente è un numero intero compreso tra -128 e 127. Non tutti i numeri possono essere espressi in questo modo. Anche OP ha chiesto un facile incremento. NSDecimalNumber non lo ha fornito. e ancora la tua risposta implica che hai bisogno di NSDecimalNumbers nello spazio oggetti. Questo è sbagliato.
vikingosegundo

Amico, stavo cercando di essere sinceramente utile con la mia risposta, e ho pensato che il voto negativo fosse perché ho sbagliato qualcosa e ho pensato che avrei potuto imparare qualcosa di nuovo. Ora vedo che non è così. I tuoi commenti non hanno senso e ti suggerisco di leggere uo sui sistemi numerici perché un numero di base 10 sys. (Ri. La tua citazione) non causerà errori di arrotondamento per i numeri base 10, non ho detto nulla sulla precisione, solo l'accuratezza, ma 128 decimale ha anche molta precisione.
lms

0

Usa una categoria per facilitarne l'uso futuro. Ecco un'idea di base.

 - (void)incrementIntBy:(int)ammount {
      self = [NSNumber numberWithInt:(self.intValue + ammount)];
 }

Ugh. Una categoria che implementa un metodo di istanza che sostituisce self?!? È davvero brutto. Perché non scrivere un metodo di istanza che abbia un ritorno non nullo del NSNumber risultante.
Duncan C

NSNumber è definito immutabile, quindi questo metodo di categoria viola la sua presunta immutabilità (anche se sostituisce self). Una categoria di questo tipo meglio progettata aggiungerebbe invece un nuovo inizializzatore a NSNumber, nella forma: + numberByIncrementingAmounf: (int) amount;
Motti Shneor

0

Molte buone informazioni nelle risposte a questa domanda. Ho usato la risposta selezionata nel mio codice e ha funzionato. Poi ho iniziato a leggere il resto dei post e ho semplificato molto il codice. È un po 'più difficile da leggere se non hai familiarità con i cambiamenti nella notazione introdotti in Xcode 5, ma è molto più pulito. Probabilmente potrei fare solo una riga, ma poi è un po 'troppo difficile capire cosa sto facendo.

Sto memorizzando un NSNumber in un dizionario e voglio incrementarlo. Lo ottengo, lo converto in un int, lo incremento mentre lo converto in un NSNumber, quindi lo rimetto nel dizionario.

Vecchio codice

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

Nuovo codice

NSNumber *correct = [scoringDictionary objectForKey:@"correct"];
scoringDictionary[@"correct"] = @(correct.intValue + 1);
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.