NSNumber to NSInteger gives wrong value? - objective-c

I have an NSNumber funds. When I do:
NSLog(#"%# %i", funds, [funds integerValue]);
I get:
4869222353 574255057
Completely different numbers. The first one is correct, so there must be something wrong with converting it to integer. What am i doing wrong?
Thanks.

Sample Code :
NSNumber *myNum = [NSNumber numberWithLongLong:4869222353];
NSLog(#"%# %lld",myNum,[myNum longLongValue]);
Why this is working?

You have overflow. Integer is 32 bit long and is signed so max value is 2147483647. Printing NSNumber does it in proper way (probably using long).

Related

Objective-C NSNumber numberWithLongLong creates integer

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?

wrong value when using objectAtIndex Objective-C

I have an array with two elements which are 50 and 60:
NSArray*array = [NSArray arrayWithObjects:
[NSNumber numberWithLong:50],
[NSNumber numberWithLong:60], nil];
when using the array later on (in fact I´m writing this array as a default list to a plist file) I do it this way:
long value = [array objectAtIndex:1];
After this value contains 15559 what I don´t understand. In the debugger [array objectAtIndex:1] clearly shows (long)60.
I´m sorry, I don´t see what´s wrong ;(
Any ideas?
Ronald
A long is not an NSNumber. If you want to set value as a long to [array objectAtIndex:1] you must convert it from an NSNumber to a long. You may wish to call longValue on the NSNumber to do that.
You may be wondering why the compiler doesn't complain and help you here. It's probably because an object in an array is fetched as an id, and so most bets are off. This is a common problem with arrays: knowing what you're fetching, and what to do with it, is up to you.
Your screen shot of the debugger is excellent. Notice that if you look at it carefully now, with your head clear, it is very clear about the difference between value which is a long, on the one hand, and array[0] which is an NSNumber wrapping a long, on the other. So the debugger was in fact answering your questions all along!
This is because you are not calling longValue on the object that you get from the array:
long value = [[array objectAtIndex:1] longValue];
What your code gets is an address of NSValue, which gets converted to a "junk" long value unrelated to the number that you stored in the array.

Making sure an NSString's numeric value will fit into a long long

I was wondering how it is possible to validate input from a UITextField in a case such as this:
NSString *str = [UItextfield1 text];
long long value = [str longLongValue];
How do I check first if the number won't wrap around, and if it is numeric before passing it on?
Don't check first, check after. The docs for longLongValue say that if the string can't be converted, value will be 0. If its magnitude would be too great, you'll get LLONG_MAX or LLONG_MIN

How to Turn Number into a String with Format?

Say I have a number, double, or NSNumber, 3.333333
I want that to turn that into #"3.3"
How would I do so?
Can I do NSString stringWithFormat? But what's the format?
NSString *str = [NSString stringWithFormat:#"%.1f", yourDouble];
or for NSNumber:
NSString *str = [NSString stringWithFormat:#"%.1f", [yourNSNumber doubleValue]];
0.0f means the amount of digits before and after the decimal. So #Wevah's answer would be correct, but keeping that in mind will save you time in the future.
%f stands for a float variable which I am sure you understand. What you would need to display this is a float variable because it contains a decimal. Like people have stated before, you will need to use %.1f
The % just tells the compiler that a special character is coming up.
The f tells the compiler that it is a float variable.
The .1 tells the compiler how many decimal places your float variable is to have. If you would want to have 6 decimal places, then you would us %.6f
Yes, you will want to use string with format.
Say you have a UILabel, then you will want to say
theLabel'sName.text = [NSString stringWithFormat:#"%.1f", ((float)int1 / int2)];
You need the (float) to tell the compiler that whatever int1 / int2 is, is a float variable.
If your NSNumber instance is called myNumber then do
[myNumber stringValue];

check if value is integer or double in objective c

I have a case where I should get the elements from an array and I do not know if the type is double or integer.
[array objectAtIndex:2]
and the problem is that I can not identify the type. If i knew the type I simply would perform:
[[item objectAtIndex:2] intValue] or
[[item objectAtIndex:2] doubleValue]
Is there any way to detect that?
Br,
Gzim
See the documentation for the -objCType method.
Basically, it returns a string describing the type contained in the NSNumber. The Objective-C runtime documentation has more information on the type codes.
However, it is quite odd to have a design where the type is unknown. I would suggest that a better solution -- possibly an interesting question -- would be to avoid the ambiguous type in the design of your application.
NSString* type = [NSString stringWithUTF8String:[valueInQuestion objCType]];
This will equal "d" if it is a double and "i" if it is an integer.