NSArray change type of NSNumber - ios

I want to store some NSNumber as double in a NSArray. So I tried that :
NSArray *diamArray = [[NSArray alloc] initWithObjects:
[NSNumber numberWithDouble:1.0],
[NSNumber numberWithDouble:1.2],
nil];
And then, I ask Xcode to show the diamArray:
NSLog(#"%#", diamArray);
And here is the result:
[8873:1153347] (
1,
"1.2"
)
So we can see that both numbers are not treated the same way. It's a problem for me as these values are usable as their type changes. Specially, in the debug watch of the array, I can see the decimal number (1.2) as "double" but the 1.0 value is shown as "null".
How can I force the array to consider 1.0 as a double ?

It can be confusing to decipher data types from NSLog as it is attempting to display convenient information. In this case, 1.0 is exactly one, so it is truncating that value so that it appears to be an Int. I'll almost guarantee that if you were to pull the item out of the array and display it's objCType you'd find that it's a double:
NSLog("%#: %s", diamArray[0], [diamArray[0] objCType]);
The other thing to consider is that values can be cast coming out of NSNumber, so even if it stores 1.0 as an integer value, you can still extract it as a double:
[diamArray[0] doubleValue]

NSNumber is a class cluster. You should not worry about how it store the information, but you should instead mostly care about how you retrieve that information.
To get back your double, you have just to do:
double myDouble = [dimArray[0] doubleValue];
but there are also:
[dimArray[0] intValue];
[dimArray[0] integerValue];
[dimArray[0] unsignedIntegerValue];
[dimArray[0] floatValue];
...

Thanks for your info and suggestions.
I find out that it's related to locale. My default locale is fr_FR and then I tried that:
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
f.numberStyle = NSNumberFormatterDecimalStyle;
NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
[f setLocale:usLocale];
NSArray *pasArray = [[NSArray alloc] initWithObjects:
[f numberFromString:[[NSNumber numberWithDouble:1.0] stringValue]],
[f numberFromString:[[NSNumber numberWithDouble:0.25] stringValue]],
nil];
and it works as expected. I guess that, due to locale difference, the dot is misinterpreted. But I think it's not really clean to do so.
My conclusion is that David Berry is right: I don't have to care about the display and rather ask for the format I need when I need it.
Thanks again to help me to understand why it wasn't a problem.

Related

What is the difference between #"1.5" and #(1.5) while setting the value in NSDictionary?

In iPhone project,
It was while I was while setting Value in dictionary,
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#(2.8) forKey:#"Why"];
AND,
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#"2.8" forKey:#"Why"];
My question is Why not #"2.5" and #(2.5) ?
You have two questions, it would be better to have a single question.
But as to the difference,#"2.5" is an NSString where #(2.5) is an NSNumber. There is a big difference between textual and numeric data.
As for why you need an NSNumber and not NSString is obvious: the kerning is a numeric value.
using the #() syntax you can box arbitrary C expressions. This makes it trivial to turn basic arithmetic calculations into NSNumber objects see below:
double x = 24.0;
NSNumber *result = #(x * .15);
NSLog(#"%.2f", [result doubleValue]);
You can also refer NSNumber object as #"" string but cant make calculations like above example. In your case both are acceptable but here calculation makes difference.
When you use
#"2.5" it's behave like a string
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#"2.8" forKey:#"Why"];;
NSString *a = [dictionary ValueforKey:#"Why"];
but when you use #(2.8) then it's behave like a NSNumber
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#(2.8) forKey:#"Why"];;
NSNumber *a = [dictionary ValueforKey:#"Why"];
#(2.8) is a type of NSNumber.
#"2.8" is a type of NSString.
Both the type and value were different between there two.

NSNumber numberFromString not placed decimals

I am trying to convert NSString to NSNumber and it seems to create a decimal point issue here.
NSString *str = #"515.51515";
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:str];
NSLog(#"Number here:%#",myNumber);
[f release];
& result print is
2015-03-01 08:09:28.353 myApp [57376:2086924] Number here: 515.5151499999999
Actual debug log picture here
but actually it should be 515.51515 rather 515.5151499999999.
I tried all comibination with f.usesSignificantDigits & f.maximumFractionDigits =10 but no luck.
please let me know How to fix this?
RMaddy is correct, floating point numbers will be a bit off.
Since an NSDecimalNumber is an NSNumber you can use:
NSNumber *number = [NSDecimalNumber decimalNumberWithString:#"515.51515"];
Try to use construction:
NSNumber *myNumber = [NSNumber numberWithFloat:[str floatValue]];
I think it should work correctly.

NSNumberFormatter numberFromString decimal number

I'm trying to parse a NSString with a NSNumberFormatter like following.
NSNumberFormatter *myFormatter = [[[NSNumberFormatter alloc] init];
NSNumber *myNumber = [myFormatter numberFromString:#"42.00000"];
numberFromString returns a NSNumber object in the simulator but not on a device.
The decimals (.00000) are causing the return value to be nil on a device because parsing 42 (without the decimals) works just fine (both in the simulator and on a device).
The reason I'm using a NSNumberFormatter is because is like how it returns nil if the string is not a valid number (which is working against me here :p). NSString doubleValue does not provide this kind of behaviour. Also, NSDecimalNumber decimalNumberWithString doesn't do the job because [NSDecimalNumber decimalNumberWithString:#"4a2.00000"] returns 4.
Any ideas why this would not work on a device?
Is it the locale? I tried setting myFormatter.numberStyle = NSNumberFormatterNoStyle and NSNumberFormatterDecimalStyle but it changes nothing.
As #rmaddy already said in a comment, the decimal separator of NSNumberFormatter is
locale dependent. If you have a fixed input format with the dot as decimal separator,
you can set the "POSIX locale":
NSNumberFormatter *myFormatter = [[NSNumberFormatter alloc] init];
[myFormatter setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
NSNumber *myNumber = [myFormatter numberFromString:#"42.00000"];
Alternatively, you can use NSScanner to parse a double value, as e.g. described
here: parsing NSString to Double
42.00000 is not a string mate, why not #"42.00000"?

How do I get NSNumber with NSLocale smarts from a UITextField?

Getting correct localized formatting of numbers to display is easy.
But prompting for a decimal number input from a UITextField is proving tricky.
Even though the decimal keypad may present the comma for European usage instead of the stop, the method handling the input apparently still needs to be locale-savvy.
my research here on S.O. and other places suggests
-(IBAction)buttonPress:(UIButton *)sender
{
NSNumber *firstNumber = #([self.firstField.text floatValue]); // 2 alternative ways
NSNumber *secondNumber = [NSNumber numberWithFloat:[self.secondField.text floatValue]];
.
.
only gives me integers to perform arithmetic with. They aren't floats at all. They have no float value
Supposing this is the only thing the app does, and I immediately do:
.
.
NSNumberFormatter *numberFormat = [[ NSNumberFormatter alloc] init];
[ numberFormat setNumberStyle:NSNumberFormatterDecimalStyle];
[ numberFormat setLocale:[NSLocale currentLocale]];
[ numberFormat setMaximumFractionDigits:2];
NSString *displayString = [ numberFormat stringFromNumber:firstNumber];
self.resultLabel.text = displayString;
}
I am throwing the input back to a label in the ViewController without any further handling to make sure the the decimals aren't hidden by not having a formatter. No Joy. Still in integers.
Obviously the app has to do something in the way of calculation, and since one can't handle NSNumber wrappers directly, I have to resolve it before i do the conversion thing:
double xD = [firstNumber doubleValue];
double yD = [secondNumber doubleValue];
the question is, where is the decimal-ness of the input being lost?
I have no problem with the desktop keyboard and the simulator, but if i set a test device to - say - Polish then that simply won't do.
EDIT:
and here's the result from the answer provided below
// run these 4 methods first, that way you can re-use *numberFormat for the display
NSNumberFormatter *numberFormat = [[ NSNumberFormatter alloc] init];
[ numberFormat setNumberStyle:NSNumberFormatterDecimalStyle];
[ numberFormat setLocale:[NSLocale currentLocale]];
[ numberFormat setMaximumFractionDigits:2];
// here 'tis
NSNumber *firstNumber = [numberFormat numberFromString:self.firstField.text];
// do the same for other input UITextFields
// sh-boom. there you go
You need use longLongValue not longValue to convert NSString to long type. or use NSNumberFormatter->numberFromString:

Converting double to string return strange value in objective c

I have an NSDictionary which consist of multiple key/pair values. One of them consist double value.
NSNumber *goalValue = [info objectForKey:#"goalValue"];
I put breakpoint and I found that goalValue store the normal value that I need.
and just below I convert it to NSSting like
NSString *stringValue=[goalValue stringValue];
and this stringValue store very strange value.
Guys please help me. I am totally puzzled, I did goggle but nothing change. Please help me. Thanks in advance.
The method stringValue will convert the NSNumber to string by internally calling descriptionWithLocale: with locale as nil and this method in turn will call initWithFormat:locale:,
From Apple docs,
To obtain the string representation, this method invokes NSString’s initWithFormat:locale: method, supplying the format based on the type the NSNumber object was created with:
So format specifier used for double is %0.16g(i.e. 16 digit precision) hence the value 98.09999999999999
I'd suggest using NSNumberFormatter,
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:2]; //2 decimal places, change this as required.
NSString *string = [numberFormatter stringFromNumber:goalValue];
Hope that helps!
To prevent this behavior, I suggest using NSDecimalNumber (also this is from my experience best format when dealing with very precise amounts)
NSDecimalNumber *doubleDecimal = [[NSDecimalNumber alloc] initWithDouble:[info objectForKey:#"goalValue"]];
for two digits formatting, use numberFormatter
NSNumberFormatter * nf = [[NSNumberFormatter alloc] init];
[nf setMinimumFractionDigits:2];
[nf setMaximumFractionDigits:2];
NSString *stringValue = [nf stringFromNumber:doubleDecimal]
Its showing the rounded value so you can round the value to single digit using NSNumberFormatter.
NSNumberFormatter *fomatter = [[NSNumberFormatter alloc] init];
[fomatter setMaximumSignificantDigits:2];
NSString *stringValue=[fomatter stringFromNumber:goalValue];

Resources