Objective-C NSNumber numberWithLongLong creates integer - objective-c

When I attempt to create an NSNumber using the numberWithLongLong with a number greater than -2 and less than 13 it returns a number that is casted as an (int).
I see this if I look at the Xcode debugger after stepping over my line.
NSNumber* numberA = [NSNumber numberWithLongLong:-2]; //Debugger shows as (long)-2
NSNumber* numberB = [NSNumber numberWithLongLong:-1]; //Debugger shows as (int)-1
NSNumber* numberC = [NSNumber numberWithLongLong:12]; //Debugger shows as (int)12
NSNumber* numberD = [NSNumber numberWithLongLong:13]; //Debugger shows as (long)13
To put my problem in context, I am using a long long value for an epoch date that I will end up serializing using BSON and sending across the wire to a webservice. The webservice requires the date to be a java Long.
Thanks in advance

You have discovered that NSNumber (actually, its CFNumber counterpart) has a cache for integers between -1 and 12 inclusive. Take a look at the CFNumberCreate function in CFNumber.c to see how it works.
It looks like you can force it not to use the cache by passing your own allocator to CFNumberCreate. You'll need to look at the CFAllocator documentation.
But note that the CFNumberCreate manual says this:
The theType parameter is not necessarily preserved when creating a new CFNumber object.
So even if you bypass the cache, you might not get back an object whose objCType is q (which means long long). It looks like the current implementation will return q but that could change in a future version.
You are allowed to write your own NSNumber subclass if you need to guarantee that objCType returns q. Read “Subclassing Notes” in the NSNumber Class Reference.

You can use your webservice without concern.
NSNumber wraps a numeric value (of primitive type) as an object. How NSNumber stores that value is not really your concern (but there is a method to find it out), it is an opaque type. However NSNumber does maintain an internal record of the type used to create it so its compare: method can follow C rules for comparison between values of different types precisely.
For integral types the integral value you get back will be exactly the same, in the mathematical sense, as the one you created the NSNumber with. You can create an NSNumber with a short and read its value back as a long long, and the mathematical value will be the same even though the representation is different.
So you can store your integral date value as an NSNumber and when you read it back as a long long you will get the right value. No need to be concerned how NSNumber represents it internally, and indeed that could potentially change in the future.
(At least one implementation of NSNumber can store values as 128-bit integers, which helps ensure correct semantics for signed and unsigned integers. Also I stressed integral types as with the vagaries of real numbers talking about mathematical exactness is somewhat moot.)

Wait. I think I know what your asking. Try it this way:
NSNumber* numberA = [NSNumber numberWithLongLong:-2LL];
NSNumber* numberB = [NSNumber numberWithLongLong:-1LL];
NSNumber* numberC = [NSNumber numberWithLongLong:12LL];
NSNumber* numberD = [NSNumber numberWithLongLong:13LL];
BTW: it won't matter what the type of the constant is, it will be coerced into a long long when passed to [NSNumber numberWithLongLong:]
UPDATE
Based on #robmayoff's answer, I don't think NSNumber is reliable for your. How are you packing your BSON? is there a way to use NSValue instead of NSNumber?

Related

What is the difference between 4 and #4?

I just started learning this, and the tutorial started off by using the # symbol before all number literals, and string literals, and I thought "Okay, Objective-C uses the # symbol before literals," but then next thing you know they used some numbers without the # sign and I was at a total loss.
(I'm saying 'number' because I'm afraid to say int since Objective-C / C has so many types of number.)
What's the difference?
Objective C is an extension of C, so it uses regular literals in places where C uses literals - i.e. for providing values of primitive types int, long, etc.
In addition, Objective C has support for NSNumber class of the Cocoa framework. Objects of this class are used to wrap primitive values for uses where an object is required - for example, to be put in a collection. Cocoa collections do not accept values of primitive types, so you need to provide an object wrapper before placing a numeric value into a collection.
Objective C did not have support for making literals of type NSNumber, so you needed to wrap literals manually, like this:
[NSNumber numberWithInt:4]
This is too much typing, especially when you need to define multiple such values to put into a collection. That is why Objective C added an alternative syntax for creating NSNumbers - the one with the # sign. So when you write #4, that's the same as writing [NSNumber numberWithInt:4], but is a lot less typing. For example, an initialization that looked like this in the old syntax
NSArray *oneTwoThree = [NSArray arrayWithObjects: [NSNumber numberWithInt:1], [NSNumber numberWithInt:2], [NSNumber numberWithInt:3], nil];
now looks like
NSArray *oneTwoThree = #[#1, #2, #3];
which is a lot more readable.
Note: the second code snippet uses the new syntax for array initialization as well.
There is a difference between a int type and an NSNumber object. An int is a data type used to store integers. You create an int like this: int i = 4;
An NSNumber is an Objective-C object that can store any type of number, and int, double, float, short, long, etc. This is created like NSNumber *num = #4;, which actually becomes NSNumber *num = [NSNumber numberWithInt: 4];
The main reason to use #4 instead of 4 is in NSArrays and NSDictionary's. You can only store objects, not types like int or float, in these objects. So if you want an array of numbers, it would have to be like [NSArray arrayWithObjects: #1, #2, #3, #4, nil];
The # has other uses as you have realized. Just like how a number becomes an object by adding the # to it, a C-String "Hello World" becomes an Objective-C object (NSString) with #"Hello World". A C-Array [1,2,3,4] becomes an Obj-C object (NSArray) with #[#1,#2,#3,#4]. Same with dictionaries: #{key,value}
If you want to learn more about literals, you can use this link, or this link.
One is a number (an int, a scalar). The other is an NSNumber (an Objective-C object; on this notation, see http://clang.llvm.org/docs/ObjectiveCLiterals.html).

Objective-C Bool Literals and Macros

Disclaimer: limited knowledge of Objective-C (passing curiosity).
if (#YES)
vs
if (YES)
What's the difference?
From what I understand, #YES is a bool object literal, and YES is a macro that expands to 1? Is this correct? If so, why use #YES instead of YES or vice versa?
#YES is a shortcut for [NSNumber numberWithBool:YES], so this:
if (#YES)
actually means
if ([NSNumber numberWithBool:YES] != nil)
Note, that it doesn't matter what number (or bool value) that is. You just test that it's a valid object. Even #NO will evaulate to YES if you test it like that, because it's a non-nil NSNumber instance:
if (#NO) NSLog(#"test");
Output:
2013-12-07 21:02:49.828 MyApp[37512:70b] test
Long story short: Don't use #YES or #NO like that, they will not behave as you would expect.
The # symbol is a recent addition to Objective-C, which changes literals into their object representation in the form of an NSNumber instance.
This is especially useful if you need to store literals in arrays and dictionaries, which can only store objects (type id).
The way you use it, there is not need to create an object for the literal, so you should just use the literal directly.
The # symbol has always been used for denoting NSString objects, and only 2-3 years ago this syntax was extended for literals and expressions.
#YES, #1, #1.5...these are all literal syntax that are the equivalent of an NSNumber ie:
[NSNumber numberWithBool:YES], [NSNumber numberWithInt:1], [NSNumber numberWithDouble:1.5].
Using this means you are creating an NSNumber object.
YES is simply the BOOL type, it's a primitive type in Obj-C, not an object like NSNumber. The BOOL type is used in Objective-C to hold true or false values. This is what you would normally use. You would only use #YES in cases where you need to hold the primitives in something that only accepts objects, perhaps if you wanted to hold them in an NSArray for example.

Errors in trying to cast to NSInteger * and NSMutableArray *

I'm a newbie in obj c. So I have a simple question.
I have a matrix of NSInteger values. It is called "curBoard". I want to update value at (x,y) coordinates with value "curStep". I have an arror "operand of type void where arithmetic..."
What am I doing wrong ?
[curBoard replaceObjectAtIndex:x withObject:(NSMutableArray *)[[curBoard objectAtIndex:x] replaceObjectAtIndex:y withObject:(NSInteger *)[NSNumber numberWithInt:curStep]]];
Update:
NSMutableArray *board;
board = [NSMutableArray new];
for(NSInteger i = 0; i<boardSize; i++) {
NSMutableArray *row = [NSMutableArray new];
for(NSInteger j = 0; j < boardSize; j++)
[row addObject:(NSInteger *)[NSNumber numberWithInt:0]];
[board addObject:row];
}
This withObject:(NSInteger *)[NSNumber numberWithInt:curStep]] part is what causing an issue. If you are storing as NSNumber objects, you should just use:
... withObject:[NSNumber numberWithInt:curStep]]
Edit:
From the code posted above, you should add it as:
[row addObject:[NSNumber numberWithInt:0]];
NSInteger is not of pointer type and you should use NSNumber itself to add to array.
Objective-C is basically just a bunch of object syntax strapped to C. The overall effect is something like strapping a jetpack to a horse: sometimes the two parts don't really work together very well. In this case, you're trying to go faster by telling the horse to giddy up, when you should really be opening up the throttle.
NSMutableArray is part of the jetpack—it's an Objective-C object and is only equipped to handle arrays of Objective-C objects. But NSInteger is part of the horse—it's a primitive C integer type, not a real object.*
I know NSInteger is capitalized like a class and has an NS prefix like a class, but it's really a creature of C. You can confirm this yourself—type Cmd-O in Xcode and type "NSInteger" into the Open Quickly dialog that pops up, and you'll be able to jump to its definition. In my current Mac project, that's typedef long NSInteger;; long is one of the primitive C types.
NSNumber exists to bridge the two. It's an object specifically designed to hold the C numeric types inside it. Since NSNumber is an object, NSMutableArray and other Objective-C things can deal with it.
But you can't just cast between NSNumber and NSInteger. NSNumber holds an NSInteger inside it, but that doesn't mean it's actually an NSInteger itself. If you put a sandwich in a plastic bag, you can't eat the bag.
Instead, you have to use NSNumber's +numberWithInteger: method to construct an NSNumber, and -integerValue to get the integer back out of it. (+numberWithInt: and -intValue will usually work, but they may behave differently with very large values, depending on whether your app is running on a 32-bit or 64-bit processor.) Actually, nowadays you can say [NSNumber numberWithInteger:foo] as #(foo) instead, which is a lot shorter.**
So when you add a number, you should be saying:
[row addObject:#(0)];
And when you later want that number back, you'll want to say something like:
n = [[row objectAtIndex:y] integerValue];
The -replaceObjectAtIndex:withObject: error is a different story. -replaceObjectAtIndex:withObject: doesn't return anything at all, so you can't use it as an argument. Luckily, you don't need to in this case. -replaceObjectAtIndex:withObject: doesn't create a new array; it alters the array that's already inside [curBoard objectAtIndex:x], so you don't need to do anything to curBoard. Instead, you can just write:
[[curBoard objectAtIndex:x] replaceObjectAtIndex:y withObject:#(curStep)];
* You actually used NSInteger *, which is slightly different. The * means "pointer to", so NSInteger * is a pointer to a primitive integer. This is sort of like NSNumber *, a pointer to an NSNumber object, so the compiler allows you to cast it.
Note that casting a pointer doesn't convert the data at the other end of the pointer; it just makes the compiler interpret the same data in a different way. If you actually tried to use the NSInteger * pointer to get data, you would either get garbage data or (for reasons too large to fit within this margin) crash.
In this case, though, once you've Jedi mind-tricked the compiler into thinking that value is a pointer to an NSInteger, you try to pass it to to -addObject:. -addObject: expects a pointer to an object, so the compiler balks at passing a pointer to an NSInteger instead.
** This syntax will work as long as you're using the iOS 6 SDK Xcode 4.4 or later, even if you actually run the app on an older iOS. It will also automatically use the right +numberWithWhatever: method for you, so you don't have to worry about picking the best one. When you're using a numeric literal like 0, the parentheses are optional, but they're required when you use a variable or constant. Of course, you can still do it the wordy way if you want, but there's little point nowadays.

NSNumber limit?

What is the highest int that NSNumber allows? I've seen the answer elsewhere on these forums hence why I'm deeply confused here.
int miles = 35000;
vehicle.mileage = [NSNumber numberWithInt:miles];
NSLog(#"int value = %d", miles);
NSLog(#"mileage = %#", vehicle.mileage);
The output is:
int value = 35000
mileage = -30536
I must be missing some terrible easy here, but can someone explain to me why this is not working correctly?
UPDATE:
After looking further, vehicle.mileage is getting set correctly to 35000 but when I display this via NSLog(#"%#", vehicle.mileage) it is outputting it incorrectly. I have yet to find the "magic" value when this stops working because as of now, it works for values up to ~30,000.
NSNumber is just a wrapper so it goes in overflow when the wrapped primitive type goes in overflow.
So if you use numberWithInt the maximum number allowed is INT_MAX (defined in limits.h), if you use a numberWithFloat the maximum number allowed is FLOAT_MAX, and so on.
So in this case you aren't going in overflow, I doubt that INT_MAX would be so low.
Overview
NSNumber is a subclass of NSValue that offers a value as any C scalar
(numeric) type. It defines a set of methods specifically for setting
and accessing the value as a signed or unsigned char, short int, int,
long int, long long int, float, or double or as a BOOL. (Note that
number objects do not necessarily preserve the type they are created
with.) It also defines a compare: method to determine the ordering of
two NSNumber objects.
So NSNumber is as big as what it wraps. For your unexpected result you can check comment bellow your qestion from #sjs.
+numberWithInt: interprets the value as signed int. Mileage would never be negative, so I suggest using [NSNumber numberWithUnsignedInt:]
The limit NSNumber integer can have is known as INT_MAXbut 35, 000 is nowhere close to that. The problem must be with vehicle object or the mileage property in the vehicle, either of them may be nil
So, go ahead and log with this conditional statement:
if (!vehicle) {
NSLog(#"Vehicle is nil");
}
else if (!vehicle.mileage) {
NSLog(#"Vehicle's mileage is nil");
}
Tell me your result

Should I use NSNumber instead of basic C number types?

What is the benefit of using NSNumber from Foundation Framework instead of basic C types (int, float, double)?
Using NSNumber:
NSNumber *intNumber;
NSInteger myInt;
intNumber = [NSNumber numberWithInteger: 100];
myInt = [intNumber integerValue];
Using pure C:
int intNumber;
intNumber = 100;
Seems a lot easier and economic to use C.
I know NSNumber is an object (or class?) type, but why would I use them instead simple C variables? When should I use them?
The purpose of NSNumber is simply to box primitive types in objects (pointer types), so you can use them in situations that require pointer-type values to work.
One common example: you have to use NSNumber if you want to persist numeric values in Core Data entities.
You can and should use primitives for calculations (unless with decimals, in which case you use NSDecimal or NSDecimalNumber).
If you need to pass a number as an object, use NSNumber.
If you need to make arithmetic operations, you can use int and double. If you don't want to bother with 32/64 bit issues, you can use NSInteger and CGFloat.
Because with dealing with passing of parameters with certain objects, using a basic data type will not work. Also, the NSNumber class gives you options for converting values into other datatypes quickly.