NSNumber returns wrong value - objective-c

I have NSDictionary and I assign value of 'price' key to NSNumber property of my object but when I log number value, it is an strange negative number!
item.price = [food valueForKey:#"price"];
price property is NSNumber
[[food valueForKey:#"price"] class]
will print __NSCFNumber which is right.
[[food valueForKey:#"price"] intValue]
returns 0x000000000000c350 which is 50000 thats right
but when I log item.price or [item.price integerValue] it is -15536 which is completely wrong!
Any idea?
food json sample:
{
"title":"Pizza",
"price":50000
}

Guess what?
all of this logs and problems shows my NSNumber property can't store some integers. but what range of integers? integers which are between -32,768 / 32,768
but why? because I have define my managed object price property of kind NSInteger 16!
I should define it as NSInteger 32

Let's say you are trying to do this:
NSDictionary *inventory = #{
#"price" : [NSNumber numberWithInt:50000]
};
NSNumber *num= [inventory valueForKey:#"price"];
NSLog(#"%d,%f,%ld,%#",num,num,num,num);
and the log will display as:
800002,-0.000000,-5764607523033434878,50000
all of them are totally different.The last one is the correct NSNumber object
NSNumber is an object ,so you need to use %# to log it and remaining %d,%f,%ld are not objects.

Related

How to divide NSObject by a number in Objective-C?

I have this code:
NSObject *distanceInMeters;
distanceInMeters = [[[[[[googleMapsApiResult objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"distance"] valueForKey:#"value"];
NSLog(#"%#", distanceInMeters); // this outputs 7578
NSDecimalNumber *roundTripInKilometers;
roundTripInKilometers = distanceInMeters / 500; // It says "Invalid operands to binary expression ('NSObject *' and 'int')
I expect to get 15.156 but it cannot divide object value with an integer. What should I do to get 15.156?
You can't divide number from NSObject, To do the same, You have to fetch the number from it and use it anywhere
NSNumber *distanceInMeters;
distanceInMeters = [[[[[[googleMapsApiResult objectForKey:#"routes"] objectAtIndex:0] objectForKey:#"legs"] objectAtIndex:0] objectForKey:#"distance"] valueForKey:#"value"];
NSLog(#"%#", distanceInMeters); // this outputs 7578
NSDecimalNumber *roundTripInKilometers = (NSDecimalNumber *)[NSDecimalNumber numberWithDouble:[distanceInMeters doubleValue] / 500.0];
There are many problems in your code. First, you need to convert the value you get from the API into an double. An easy way to do that would be to first convert it to an instance of NSString. Then get an double from the string with the method doubleValue.
Next divide that value by 500:
double roundTripInKilometersDouble = distanceInMeters / 500.0;
Then put that result into an NSDecimalNumber:
NSDecimalNumber *roundTripInKilometers = [NSDecimalNumber numberWithDouble: roundTripInKilometersDouble];
(Haven't tested this code.)

arc4random in NSNumber giving negative values?

I'm creating a random number and storing it in a NSNumber object like this:
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(2^32-1)];
I also tried:
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(4294967295)];
NSNumber *index = #(arc4random_uniform(4294967295));
At some point I'm also assigning the number 1 like this:
NSNumber *index = #(1);
This should give me only positive numbers.
Later on, I print out these numbers like this:
NSString *string = [NSString stringWithFormat:#"%#", index];
This gives me some negative values for the random numbers and 1 is being printed as 1. So I though maybe if I do:
NSString *string = [NSString stringWithFormat:#"%u", index.unsignedIntValue];
I'll get only positive numbers - which I do - but now 1 is suddenly being printed as some large positive number, also.
What's going on here? How can I correctly store a u_int32 (which arc4random returns) in a NSNmber and make sure that they are only positive?
Use
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(exp2(32)-1)];
I never get any negative numbers. arc4random_uniform(x) always returns a number between 0 and x, and the stringvalue of the NSNumber generated from it is correct.
EDIT: replaced exp2(31) with exp2(32)
You said in a comment that the index is stored in a Core Data entity as an "Integer 32" attribute, and I assume that is where the problem comes from.
Core Data dynamically generates getter and setter methods for all attributes (and relationships) of managed object classes. These accessor methods are different from the "usual" #synthesized accessor methods which are backed up by an instance variable.
For an "Integer 32" attribute, Core Data uses a (signed) integer for the attribute, and when you set a value, it is just cast or truncated to int. Example:
e.index = [NSNumber numberWithUnsignedInt:0xFFFFFFF0U];
// This would give the same result:
// e.index = [NSNumber numberWithLongLong:0x1234FFFFFFF0LL];
NSNumber *val = e.index;
NSLog(#"value=%#, type=%s", val, [val objCType]);
// Output: value=-16, type=i
The output type=i shows that the value contains an int.
If you need unsigned integers in the range 0 .. 2^32-1, then you can either (as you already did) use unsignedIntValue:
unsigned x = [val unsignedIntValue];
or store the attribute as "Integer 64".
Remarks:
I am fairly sure that this is not a problem of arc4random_uniform.
In your first code example arc4random_uniform(2^32-1), you should note that ^ is exclusive-or, not exponentiation.

Adding negative NSNumber value to a NSDictionary

As someone who has some programming experience it pains me to be asking this question. I just started playing around with objective-c a few days ago and I am trying to simply add NSNumber objects to an NSDictionary. The problem is, when I add an NSNumber object with a negative value it seems as if it is being added as a string not an NSNumber.
Here is how I am initializing the dictionary:
testDict = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithDouble:-3],#"x",
[NSNumber numberWithDouble:7, #"a",
nil];
I guess I really have two questions, 1.) Is this not how you create an NSNumber object that has a negative value?
2.) When I print out the dictionary I get the following:
NSLog(#"dictionary = %#", self.testDict);
a = 7;
x = "-3";
Why the double quotes around the -3?
You're correct, and everything's fine. That's just the dictionary -description being misleading.
To verify, break on the NSLog() and try (warning: typed on iPhone):
p [testDict objectForKey:#"x"];
It should reveal it to be an NSNumber instance.
#Conrad Shultz is right, it's just an artifact of how the the description method for the NSDictionary prints the dictionary contents (which is what is happening when you pass the dictionary to NSLog)
Another way to verify that everything is really working as expected is to iterate through the dictionary members and print the descriptions of the indivdual objects. Then you can see your negative number description looks like a number rather than a string.
NSDictionary* testDict = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithDouble:-3],#"x", [NSNumber numberWithDouble:7], #"a", nil];
NSArray *keys = [testDict allKeys];
for (NSString *key in keys) {
NSLog(#"%# => %#", key, [testDict objectForKey:key]);
}
Console output is:
2012-02-29 12:38:39.544 test10[1055:f803] x => -3
2012-02-29 12:38:39.546 test10[1055:f803] a => 7

how to operate on NSNumber in NSNArray created by NSString

i've got some method.
....{
NSString *mean = #"1:1:1:1:1:1:1:1:1";
tab = [self moveSourceArrayToDestinationArray:mean];
....}
-(NSArray*)moveSourceArrayToDestinationArray:(NSString*)sourceArray{
NSArray *destinationArray = [sourceArray componentsSeparatedByString:#":"];
for (NSNumber *number in destinationArray) {
sum += [number doubleValue];
}
NSLog(#"%d", [destinationArray objectAtIndex:1] * 5); // invalid operands to binary expression ('id' and 'int')
return destinationArray;
}
how can i do something mathematic operation on numbers in NSArray?
Your reference to NSNumber in your code is a mistake, and you got lucky that your code didn't throw an unrecognized selector exception. Your destinationArray is an array of NSStrings, not NSNumbers. It just so happens that both NSString and NSNumber have doubleValue and intValue methods. So when you say [number doubleValue] in your loop, you actually end up calling [NSString doubleValue] which of course still returns the number you want. However, if you were to try to call [number shortValue], where shortValue is a selector that only exists in NSNumber and not NSString, your code would throw an exception and not work.
The moral of this answer is that you should remove any reference to NSNumber in your code, or actually convert the objects in destinationArray to NSNumbers. Otherwise, you risk running into more trouble.
The easiest thing to do is to retrieve a numeric value from the NSNumber object, something you already did in your code snippet earlier. For example, try:
NSLog(#"%d", [[destinationArray objectAtIndex:1] intValue] * 5);
See the full list of numeric access functions in the NSNumber documentation under the section titled "Accessing Numeric Values."
Your object at [destionationArray objectAtIndex:index] is likely to be a NSNumber as well. Therefore, you have to to [[destinationArray objectAtIndex:index] doubleValue]at this point, too.

How to Properly set an integer value in NSDictionary?

The following code snippet:
NSLog(#"userInfo: The timer is %d", timerCounter);
NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:timerCounter] forKey:#"timerCounter"];
NSUInteger c = (NSUInteger)[dict objectForKey:#"timerCounter"];
NSLog(#"userInfo: Timer started on %d", c);
produces output along the lines of:
2009-10-22 00:36:55.927 TimerHacking[2457:20b] userInfo: The timer is 1
2009-10-22 00:36:55.928 TimerHacking[2457:20b] userInfo: Timer started on 5295968
(FWIW, timerCounter is a NSUInteger.)
I'm sure I'm missing something fairly obvious, just not sure what it is.
You should use intValue from the received object (an NSNumber), and not use a cast:
NSUInteger c = [[dict objectForKey:#"timerCounter"] intValue];
Dictionaries always store objects. NSInteger and NSUInteger are not objects. Your dictionary is storing an NSNumber (remember that [NSNumber numberWithInteger:timerCounter]?), which is an object. So as epatel said, you need to ask the NSNumber for its unsignedIntegerValue if you want an NSUInteger.
Or like this with literals:
NSUInteger c = ((NSNumber *)dict[#"timerCounter"]).unsignedIntegerValue;
You must cast as NSNumber first as object pulled from dictionary will be id_nullable and so won't respond to the value converting methods.