109

How do I increment a NSNumber?

i.e. myNSNumber++

hexacyanide
  • 88,222
  • 31
  • 159
  • 162
TheLearner
  • 19,387
  • 35
  • 95
  • 163
  • 2
    Remember: when using `NSNumber *`, always check to see if the primitive types will suffice. – W.K.S Jan 18 '13 at 17:52
  • 1
    I am surprised that there is no answer providing fast/optimized way of doing that, because just to increase value you need to query,combine and create new object, so doing this in loop can become time consuming. – PetrV Jun 14 '14 at 12:00

9 Answers9

128

NSNumber objects are immutable; the best you can do is to grab the primitive value, increment it then wrap the result in its own NSNumber object:

NSNumber *bNumber = [NSNumber numberWithInt:[aNumber intValue] + 1];
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
125

Update: FYI, I personally like BoltClock's and DarkDusts's one-line answers better. They're more concise, and don't require additional variables.


In order to increment an NSNumber, you're going to have to get its value, increment that, and store it in a new NSNumber.

For instance, for an NSNumber holding an integer:

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

Or for an NSNumber holding a floating-point number:

NSNumber *number = [NSNumber numberWithDouble:...];
double value = [number doubleValue];
number = [NSNumber numberWithDouble:value + 1.0];
Itai Ferber
  • 28,308
  • 5
  • 77
  • 83
79

For anyone who is using the latest version of Xcode (writing this as of 4.4.1, SDK 5.1), with the use of object literals, you can clean the code up even a little bit more...

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

Still kind of a pain to deal with the boxing and unboxing everything to do simple operations, but it's getting better, or at least shorter.

Itai Ferber
  • 28,308
  • 5
  • 77
  • 83
shortstuffsushi
  • 2,271
  • 19
  • 33
  • 6
    @softRli Check out http://clang.llvm.org/docs/ObjectiveCLiterals.html to see more ObjC Literals! Very handy imo. – chown Nov 26 '12 at 19:14
  • 1
    And for that matter you could use x - @(x.intValue+1), although many people don't like using dot notation to invoke non-property methods. It's shorter, but could be called abuse of the dot notation. – Duncan C Jan 16 '14 at 13:50
  • @boulder_ruby, it is reassignment. NSNumbers are immutable, so to "increment" the value, you actually must reassign it to a new value. – shortstuffsushi Feb 24 '14 at 18:56
30

NSNumbers are immutable, you have to create a new instance.

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

// EDIT: With modern syntax:
myNSNumber = @([myNSNumber longLongValue] + 1);
Arjay Waran
  • 433
  • 5
  • 9
DarkDust
  • 90,870
  • 19
  • 190
  • 224
24

Put them all together, and you have:

myNSNumber = @(myNSNumber.intValue + 1);
JLundell
  • 1,580
  • 11
  • 14
  • aren't you reassigning myNSNumber's value here? I thought that wasn't allowed because `NSNumber` objects are immutable(?) – boulder_ruby Feb 23 '14 at 01:17
  • 1
    You're creating a new NSNumber object. myNSNumber is a pointer (NSNumber *), and has a new value when you're done. – JLundell Feb 24 '14 at 01:55
3

I like the dot expression because it is more concise and that is why IOS supports it in the first place:

myNSNumber = [NSNumber numberWithInt:myNSNumber.intValue + 1];
TheTiger
  • 13,264
  • 3
  • 57
  • 82
jack
  • 731
  • 7
  • 8
  • dot notation is not doing what you think, and may be slower at times (it could default to "valueForKey:" if no synthesised accessor exists for the "property" (in your case intValue) exists. intValue was never defined as as @property of NSNumber. – Motti Shneor Jul 21 '20 at 09:19
2

If you're using it to store an integral value:

myNSNumber = @(myNSNumber.longLongValue + 1);

For floating point stuff the short answer is the following, but it's a bad idea to do this, you'll loose precision and if you're doing any kind of comparison later like [myNSNumber isEqual:@(4.5)] you might be surprised:

myNSNumber = @(myNSNumber.floatValue + 1);

If you need to do math on floating point numbers represented as objects in Objective-C (i.e. if you need to put them in arrays, dictionaries, etc.) you should use NSDecimalNumber.

lmirosevic
  • 15,787
  • 13
  • 70
  • 116
  • If you're going to downvote, might as well be constructive and say why. – lmirosevic Jun 07 '13 at 11:54
  • Your answer implies that it is NSNumber that introduces rounding woes. That is not correct, NSNumber has the same rounding behavior as scalar types. Also your advice to use NSDecimalNumbers is quite irritating. There you imply that those are necessary if you need first citizen objects in onmbjective-c. But of course nsnumbers at objects as well. NSDecimalNumbers have a higher precision, but rounding error also might occur with them. And: op asks about incrementing, your answer with float and double arithmetic. But those have no increment, as they have no natural sucessor. – vikingosegundo Jun 07 '13 at 12:21
  • @vikingosegundo It's converting an NSNumber to a float that causes the accuracy loss because NSNumber stores numbers abstractly where float are base2, so it's not the NSNumber's fault, but that of the conversion back and forth. And NSDecimalNumbers will *not* cause rounding errors for base10 arithmetic, and they *are* designed for arithmetic, read the doc. The OP asked about incrementing an NSNumber, and I gave him a correct and readable answer for the integral case, and also gave an answer for the floating point case but advised against it and then followed up with a better suggestion. – lmirosevic Jun 08 '13 at 17:08
  • *An instance can represent any number that can be expressed as mantissa x 10 exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer between -128 and 127.* Not every number can be expressed like this. Also OP asked for easy incrementing. NSDecimalNumber do not provided that. and still your answer implies that you need NSDecimalNumbers in object space. that is wrong. – vikingosegundo Jun 08 '13 at 18:03
  • Dude I was trying to be genuinely helpful with my answer, and thought the downvote was because I got something wrong and I thought I might learn something new. I can see now thats not the case. Your comments make no sense and I suggest you have a read uo on number systems because a base 10 number sys. (Re. your quote) will not cause any rounding errors for base 10 nums, I said nothing about precision, just accuracy, but 128 decimal is has plenty precision too. – lmirosevic Jun 08 '13 at 22:50
  • you are just not answering the question. OP wants to increment an integer value. and you over complicating things with float value and NSDecimalNumbers. and yes: there might be loss of precision for base 10 calculations (hint: devide small base 10 number by a huge one — of course not every result can be expressed, as the computer's resources aren't endless.) – vikingosegundo Jun 09 '13 at 13:41
0

Use a category to ease future use. Here is a basic idea.

 - (void)incrementIntBy:(int)ammount {
      self = [NSNumber numberWithInt:(self.intValue + ammount)];
 }
nizx
  • 690
  • 1
  • 6
  • 13
  • 1
    Ugh. A category that implements an instance method that replaces self?!? That's seriously nasty. Why not write an instance method that has a non-void return of the resulting NSNumber. – Duncan C Jan 16 '14 at 13:52
  • NSNumber is defined to be immutable, hence this category method is violating its supposed immutability (even if replacing self). A better designed such category would instead add a new initialiser to NSNumber, in the form: +numberByIncrementingAmounf:(int)amount; – Motti Shneor Jul 21 '20 at 09:17
0

Lots of good info in the answers to this question. I used the selected answer in my code and it worked. Then I started reading the rest of the posts and simplified the code a lot. It’s a bit harder to read if you aren’t familiar with the changes in notation that were introduced in Xcode 5, but it’s a lot cleaner. I probably could make it just one line, but then it’s a little too hard to figure out what I’m doing.

I’m storing an NSNumber in a dictionary and I want to increment it. I get it, convert it to an int, increment it while converting it to an NSNumber, then put it back into the dictionary.

Old Code

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

New code

NSNumber *correct = [scoringDictionary objectForKey:@"correct"];
scoringDictionary[@"correct"] = @(correct.intValue + 1);
JScarry
  • 1,507
  • 1
  • 13
  • 25