objective C get Decimal from Json object - objective-c

I am trying to parse a json value to a decimal with no success. I am using the following framework
http://code.google.com/p/json-framework/
and my code is as follows
NSDecimal RRP = [[jProduct objectForKey:#"Price"] decimalValue];
NSLog(#"%#", RRP);
I get
Program received signal: “EXC_BAD_ACCESS”.
Just to test I thought I would try this:
NSLog(#"%#", [jProduct objectForKey:#"Price"]);
42.545
I get the value but obviously I have not set the NSDecimal.
Anybody else had similar experince or can see what I am doing wrong?
Thanks

I'm not familiar with the framework you are using but I would suggest the following:
What is the type returned by [jProduct objectForKey:#"price"]?
You probably need to work around the fact that this is the wrong type - maybe a an NSString?
Try:
NSDecimal RRP = [[NSDecimalNumber decimalNumberWithString:[jProduct objectForKey:#"Price"] decimalValue];
Edit:
Oh and NSDecimal is a struct, not an object so you shouldn't be using NSLog(#"%#"); as the %# format identifier is for objects.. Instead you can use the basic type format identifiers such as %d or %i and access the components of the structure individually.
However, as you probably want to log a decimal rather than the components of the struct (sign, mantissa etc) then you will probably want to convert it back to an NSDecimalNumber (which is an object).
So it becomes:
NSLog(#"%#", [NSDecimalNumber decimalNumberWithDecimal:RRP]);

[jProduct objectForKey:#"Price"]
may be a NSString. NSString respond to:
– doubleValue
– floatValue
– intValue
– integerValue
– longLongValue
– boolValue
not decimalValue
Verify the class of your data.

store the value in NSNumber
NSNumber *num = [jProduct objectForKey:#"Price"];

An NSDecimal is a struct, not an object. If you want to print an NSDecimal, use NSDecimalString():
NSDecimal rrp = [[jProduct objectForKey:#"Price"] decimalValue];
NSLog(#"%#", NSDecimalString(rrp));

See Decimal & JSON example. I think it will help you.

Related

Weird NSNumber allocation expression

Consider the following NSNumber instances:
NSNumber *b1 = #((long)(-61));
NSNumber *b2 = #((long)(-62));
NSLog(#"%#", b1);
NSLog(#"%#", b2);
The “Variables View” within the “Debug Area” shows curious values:
Does someone has any idea about this debugger infomation?
0xffffffffffffffc3 is the hex representation of -61.
0x00ffffffffffffc3 is the hex representation of 72057594037927875.
The “Variables View” within the “Debug Area” simply has troubles correctly representing negative long values of a NSNumber.
What’s ironic is that if you use an unsigned long for the underlying value for the NSNumber (see value4/b4 in above screen snapshot), the variables view will now show it as -61.
But, this is just a bug in the display of the NSNumber instances in the “Variables View”. The actual NSNumber values are fine.

Acquiring NSInteger Value

I am trying to grab the value of an NSInteger and set a UILabel value to it. The code is as follows:
counter_.text = [NSString stringWithFormat:#"%#", [counterAmount intValue]];
where counter_ is my label and counterAmount is my NSInteger. I keep getting a "Receiver type 'NSInteger *' (aka 'int *') is not 'id' or interface pointer, consider casting it to id.
I'm not quite sure how to understand this. I appreciate of your help.
intValue is an NSNumber method that returns a C primitive value. %# prints objects. In order to output a C primitive value you have to supply the type in the formatting string. %d is the type for signed integer.
As per the question, and as pointed out to me quite correctly by borrden below, the type being dealt with here is NSInteger rather than NSNumber. In iOS NSInteger is a typedef of int, so you're dealing directly with a primitive type. The NS prefix does not mean that its an object.
Since counterAmount is a NSInteger, you can not use intValue on it (since it isn't an object, you can't send any messages to it, actually).
Instead, use:
counter_.text = [NSString stringWithFormat:#"%d", counterAmount];
Now that being said, if you are displaying this value to a user you should really be using a number formatter so that it is formatted the way that they have set it up to display in the settings app:
NSNumber *number = [NSNumber numberWithInt:counterAmount];
NSNumberFormatter *formatter = [NSNumberFormatter new];
formatter.numberStyle = NSNumberFormatterDecimalStyle; // Or whichever style is appropriate for your number.
counter_.text = [formatter stringFromNumber:number];

What's the real type? NSString or NSNumber

I have a NSDictionary that contains data converted from json data, like {"message_id":21}.
then I use NSNumber *message_id = [dictionary valueForKey:#"message_id"] to get the data.
but when I use this message_id,
Message *message = [NSEntityDescription ....
message.messageId = message_id;
I got the runtime error, assigning _NSCFString to NSNumber,
so I have to use NSNumberFormatter to do the conversion.
NSString *messageId = [dictionary valueForKey:#"message_id"];
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterNoStyle];
message.messageId = [f numberFromString:messageId];
this code works.
but when I was debugging, I saw message_id of
NSNumber *message_id = [dictionary valueForKey:#"message_id"]
has a valid value, 21.
Can anyone see the problem here?
You are trying to save a NSString to a NSNumber. If you want it as an NSNumber you can do:
NSNumber *message_id = [NSNumber numberWithInt:[[dictionary valueForKey:#"message_id"] intValue]];
This should solve your problem.
What library are you using to do the conversion? {"message_id":21} means that an NSNumber with a value of 21 should be returned as an NSNumber, {"message_id":"21"} should return it as an NSString.
Using a number formatter is total overkill. Use the method "integerValue" which works just fine both with NSString* and with NSNumber* - you will get the integer 21, whether the object is NSString or NSNumber. The formatter code will obviously run into trouble if your object is an NSNumber and not an NSString.
So: message.messageId = [[NSNumber numberWithInteger:[messageId integerValue]];
I'd probably add a category to NSDictionary
(NSNumber*)nsIntegerNumberForKey:(NSString*)key
which handles the situations where the key is not present, or where the value is a null value or a dictionary or array, so you can use it everywhere you need an NSNumber with an integer value from a JSON document and have error checking everywhere.
Read here SAVING JSON TO CORE DATA and JSON official page
The JSON standard is quite clear about how to distinguish strings from
numbers– basically, strings are surrounded by quotes and numbers are
not. JSON web services however, are not always good about following this requirement. And even when they are, they are not always consistent from one record to another.
So if you have receive NSNumber where NSString is preferred, you must inspect and fix yourself

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.

need help converting an MPMediaItemPropertyPersistentID to a string and back again

I'm getting the ID of a media item from the MPMediaPickerController. According to the documentation, this value is an NSNumber object containing a uint64_t (unsigned long long). I would like to convert it to an NSString for saving in my data model. However, when I convert it to a string its value changes, and when I convert it back to a number it changes again! Obviously I'm not understanding something about these data types. Can you help?
MPMediaItem *mediaPicked;
// set mediaPicked to an MPMedia item using MPMediaPickerController...
NSLog(#"id as number: %qu", [mediaPicked valueForProperty:MPMediaItemPropertyPersistentID]); // outputs 566042331449280
NSLog(#"id as string: %#", [[mediaPicked valueForProperty:MPMediaItemPropertyPersistentID] stringValue]); // outputs 16204893883745507648
NSLog(#"id as number: %qu", [[[mediaPicked valueForProperty:MPMediaItemPropertyPersistentID] stringValue] longLongValue]); // outputs 9223372036854775807
If I try to play the media item before this conversion, it always works. But if I try to play the media item after this conversion, only about half of the media items I've tried work. So some ID values survive the conversion and some don't.
You are starting by saying this:
NSLog(#"id as number: %qu", [mediaPicked valueForProperty:MPMediaItemPropertyPersistentID]); // outputs 566042331449280
But that's wrong. %qu means "this thing is an unsigned long long". But this thing is not an unsigned long long. It's an object! It's an NSNumber wrapped around an unsigned long long. You are lying to NSLog, so you're getting garbage output in your very first statement.
Now, try this on your own machine:
uint64_t x = 16204893883745507648ULL;
NSLog(#"%qu", x);
NSNumber* n = [NSNumber numberWithUnsignedLongLong:x];
NSLog(#"%#", n);
NSLog(#"%#", [n stringValue]);
All of those NSLog statements give the same result - because they are all correct formulations, unlike the one you started with. So, those NSLog statements show you the kind of thing you ought to be saying.
Now, you might think: Oh, great, so I can get from an NSNumber to an NSString with stringValue after all. Yes, but you can't get back again. We cannot get from [n stringValue] to a correct NSNumber by using longlongValue, because a long long is not an unsigned long long. There is no unsignedLonglongValue. So you can't get there from here.
So what's the right thing to do? Don't convert at all! You've got an NSNumber, it's valid, just keep it and use it. An NSNumber is a value you can store in your model. (For example, it can go into a dictionary as a value or as a key, it can be a value in user defaults, and so on.)