Jak zwiększyć numer NSNumber

108

Jak zwiększyć numer NS?

tj. myNSNumber ++

TheLearner
źródło
2
Pamiętaj: podczas używania NSNumber *zawsze sprawdzaj, czy typy pierwotne wystarczą.
WKS
1
Dziwię się, że nie ma odpowiedzi zapewniającej szybki / zoptymalizowany sposób zrobienia tego, ponieważ aby zwiększyć wartość, należy zapytać, połączyć i utworzyć nowy obiekt, więc robienie tego w pętli może być czasochłonne.
PetrV

Odpowiedzi:

123

Aktualizacja: FYI, osobiście bardziej lubię jednowierszowe odpowiedzi BoltClock i DarkDusts. Są bardziej zwięzłe i nie wymagają dodatkowych zmiennych.


Aby zwiększyć wartość an NSNumber, będziesz musiał uzyskać jego wartość, zwiększyć ją i zapisać w nowym NSNumber.

Na przykład w przypadku NSNumberposiadania liczby całkowitej:

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

Lub w przypadku NSNumberposiadania liczby zmiennoprzecinkowej:

NSNumber *number = [NSNumber numberWithDouble:...];
double value = [number doubleValue];
number = [NSNumber numberWithDouble:value + 1.0];
Itai Ferber
źródło
62
Jest to główny powód, dla którego nienawidzę właściwości NSNumber w danych podstawowych. NSNumber jest bardzo niewygodny w pracy z matematyką.
Christian Schlensker
ponownie NSNumber nie działał podczas inicjalizacji z zerem, daje wartość śmieci.
Jignesh B
przepraszam, co to ...oznacza? To odniesienie do pseudokodu, prawda? XCode nie...
boulder_ruby
@boulder_ruby To ...tylko symbol zastępczy dla dowolnej liczby.
Itai Ferber
126

NSNumberobiekty są niezmienne; najlepsze, co możesz zrobić, to pobrać wartość pierwotną, zwiększyć ją, a następnie zawinąć wynik we własny NSNumberobiekt:

NSNumber *bNumber = [NSNumber numberWithInt:[aNumber intValue] + 1];
BoltClock
źródło
28
Języki nowożytne: 1, Objective-C: 0.
devios 1
77

Dla każdego, kto używa najnowszej wersji Xcode (pisząc to od 4.4.1, SDK 5.1), używając literałów obiektowych, można wyczyścić kod nawet trochę bardziej ...

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

Wciąż trochę uciążliwe radzenie sobie z boksowaniem i rozpakowywaniem wszystkiego, aby wykonywać proste operacje, ale jest coraz lepiej lub przynajmniej krócej.

shortstuffsushi
źródło
6
@softRli Sprawdź clang.llvm.org/docs/ObjectiveCLiterals.html, aby zobaczyć więcej literałów ObjC! Bardzo poręczne imo.
chown
1
A jeśli o to chodzi, możesz użyć x - @ (x.intValue + 1), chociaż wiele osób nie lubi używać notacji kropkowej do wywoływania metod niebędących własnością. Jest krótszy, ale można go nazwać nadużyciem notacji kropkowej.
Duncan C
@boulder_ruby, to zmiana przeznaczenia. Numery NS są niezmienne, więc aby „zwiększyć” wartość, w rzeczywistości należy ponownie przypisać ją do nowej wartości.
shortstuffsushi
30

Numery NS są niezmienne, musisz utworzyć nową instancję.

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

// EDIT: With modern syntax:
myNSNumber = @([myNSNumber longLongValue] + 1);
DarkDust
źródło
24

Połącz je wszystkie razem i masz:

myNSNumber = @(myNSNumber.intValue + 1);
JLundell
źródło
czy nie zmieniasz tutaj wartości myNSNumber? Pomyślałem, że to niedozwolone, ponieważ NSNumberobiekty są niezmienne (?)
boulder_ruby
1
Tworzysz nowy obiekt NSNumber. myNSNumber jest wskaźnikiem (NSNumber *) i ma nową wartość, gdy skończysz.
JLundell,
3

Podoba mi się wyrażenie z kropką, ponieważ jest bardziej zwięzłe i dlatego IOS obsługuje je w pierwszej kolejności:

myNSNumber = [NSNumber numberWithInt:myNSNumber.intValue + 1];
Jacek
źródło
notacja z kropką nie robi tego, co myślisz, i może czasami być wolniejsza (może domyślnie mieć wartość „valueForKey:”, jeśli nie istnieje żaden zsyntetyzowany akcesor dla „właściwości” (w twoim przypadku intValue). Wartość intValue nigdy nie została zdefiniowana jako @property of NSNumber.
Motti Shneor
2

Jeśli używasz go do przechowywania wartości integralnej:

myNSNumber = @(myNSNumber.longLongValue + 1);

Dla rzeczy zmiennoprzecinkowych krótka odpowiedź jest następująca, ale to zły pomysł, stracisz precyzję i jeśli będziesz robić jakiekolwiek porównania później, jak [myNSNumber isEqual: @ (4.5)], możesz być zaskoczony :

myNSNumber = @(myNSNumber.floatValue + 1);

Jeśli potrzebujesz matematyki na liczbach zmiennoprzecinkowych reprezentowanych jako obiekty w Objective-C (tj. Jeśli chcesz umieścić je w tablicach, słownikach itp.), Powinieneś użyć NSDecimalNumber.

lms
źródło
Jeśli zamierzasz głosować przeciw, równie dobrze możesz być konstruktywny i powiedzieć dlaczego.
lms,
Twoja odpowiedź sugeruje, że to NSNumber wprowadza zaokrąglające nieszczęścia. To nie jest poprawne, NSNumber ma takie samo zachowanie zaokrąglania jak typy skalarne. Również Twoja rada dotycząca używania NSDecimalNumbers jest dość irytująca. Tam sugerujesz, że są one konieczne, jeśli potrzebujesz obiektów pierwszego obywatela w onmbjective-c. Ale oczywiście nnumery też na obiektach. NSDecimalNumbers mają wyższą precyzję, ale mogą również wystąpić błędy zaokrąglania. I: op pyta o inkrementację, twoją odpowiedź z liczbą zmiennoprzecinkową i podwójną arytmetyką. Ale ci nie mają przyrostu, ponieważ nie mają naturalnego następcy.
vikingosegundo
@vikingosegundo Konwertuje NSNumber na zmiennoprzecinkowy, co powoduje utratę dokładności, ponieważ NSNumber przechowuje liczby abstrakcyjnie, gdzie float to base2, więc nie jest to wina NSNumber, ale konwersji tam iz powrotem. NSDecimalNumbers nie spowoduje błędów zaokrągleń dla arytmetyki z podstawą 10 i są one przeznaczone do arytmetyki, przeczytaj dokumentację. OP zapytał o zwiększenie numeru NS, a ja udzieliłem mu poprawnej i czytelnej odpowiedzi na przypadek integralny, a także udzieliłem odpowiedzi w przypadku przypadku zmiennoprzecinkowego, ale odradziłem to, a następnie podałem lepszą sugestię.
lms,
Instancja może reprezentować dowolną liczbę, którą można wyrazić jako mantysa x 10 wykładnik, gdzie mantysa jest dziesiętną liczbą całkowitą o długości do 38 cyfr, a wykładnik jest liczbą całkowitą z zakresu od -128 do 127. Nie każdą liczbę można wyrazić w ten sposób. OP poprosił również o łatwe zwiększanie wartości. NSDecimalNumber tego nie zapewniło. i nadal twoja odpowiedź sugeruje, że potrzebujesz NSDecimalNumbers w przestrzeni obiektów. to jest złe.
vikingosegundo
Koleś, starałem się być naprawdę pomocny w udzielaniu odpowiedzi i pomyślałem, że negatywny głos wynikał z tego, że zrobiłem coś nie tak i pomyślałem, że mogę się nauczyć czegoś nowego. Teraz widzę, że tak nie jest. Twoje komentarze nie mają sensu i sugeruję, abyś zapoznał się z systemami liczbowymi, ponieważ podstawowa liczba 10 sys. (Ad. Cytat) nie spowoduje żadnych błędów zaokrągleń dla liczb o podstawie 10, nie powiedziałem nic o precyzji, tylko dokładność, ale 128 miejsc po przecinku też ma dużą precyzję.
lms,
0

Użyj kategorii, aby ułatwić przyszłe użycie. Oto podstawowa idea.

 - (void)incrementIntBy:(int)ammount {
      self = [NSNumber numberWithInt:(self.intValue + ammount)];
 }
nizx
źródło
Fuj. Kategoria, która implementuje metodę instancji, która zastępuje self?!? To naprawdę paskudne. Dlaczego nie napisać metody instancji, która zwraca wynikowy numer NSNumber inny niż void.
Duncan C
NSNumber jest zdefiniowane jako niezmienne, dlatego ta metoda kategorii narusza jej rzekomą niezmienność (nawet jeśli zastępuje self). Lepiej zaprojektowana taka kategoria zamiast tego dodałaby nowy inicjator do NSNumber w postaci: + numberByIncrementingAmounf: (int) amount;
Motti Shneor
0

Wiele dobrych informacji w odpowiedziach na to pytanie. Użyłem wybranej odpowiedzi w moim kodzie i zadziałało. Potem zacząłem czytać resztę postów i bardzo uprościłem kod. Trochę trudniej jest przeczytać, jeśli nie znasz zmian w notacji wprowadzonych w Xcode 5, ale jest o wiele czystszy. Prawdopodobnie mógłbym zrobić to tylko w jednej linijce, ale wtedy jest trochę zbyt trudno zrozumieć, co robię.

Przechowuję numer NSNumber w słowniku i chcę go zwiększyć. Rozumiem, konwertuję na int, zwiększam podczas konwertowania do NSNumber, a następnie umieszczam z powrotem w słowniku.

Stary kod

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

Nowy kod

NSNumber *correct = [scoringDictionary objectForKey:@"correct"];
scoringDictionary[@"correct"] = @(correct.intValue + 1);
JScarry
źródło