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

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:

Related

NSNumberFormatter with number style NSNumberFormatterCurrencyStyle trouble with commas

I'm trying to do things right with input expenses on some items. So, when working on a device using a locale that uses comma separated decimals (the decimal pad automatically sets comma ',' instead of dot '.' for the user to input) I store the value using core data in a double variable converting the text this way:
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
[f setMaximumFractionDigits:2];
NSNumber * gasto = [f numberFromString:(((UITextField*) [cell viewWithTag:11]).text)];
destino.nuevaTrans.gasto = [gasto doubleValue];
//destino.nuevaTrans is the managed object, nothing weird there, just storing the decimal value
But when taking the value out of the stored objects and showing them in a table view I'm losing the decimals because of the comma separated locale settings (?). Doing it this way:
etiq = (UILabel*) [cell.contentView viewWithTag:12];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
etiq.text = [numberFormatter stringFromNumber:#(trans.gasto)];
//debugging console output:
//remmember, trans.gasto is only a double
NSLog(#"a: %f, b: %#", trans.gasto ,[numberFormatter stringFromNumber:#(trans.gasto)]);
The output on the simulator that is using dot '.' locale settings works fine, but when deploying on the device that is using comma ',' settings the NSNumberFormatter doesn't seem to translate it correctly to currency style.
//output on the simulator:
2014-09-07 15:00:47.561 iSpend[3930:60b] a: 2.990000, b: $2.99
//output on the device:
2014-09-07 15:02:40.005 iSpend[1389:60b] a: 2.170000, b: ₡2
So, I could try and hack this thing out... But I'm looking for a better programming practice here. Every suggestion is appreciated! Thanks!
Each Locale determines if it shows cents or just Krona. So, if you want to force it to show digits after the comma, add the line:
[numberFormatter setMinimumFractionDigits:2];
to get two digits after comma.
But the example you show has correct output.
u can try to set separator clearly: [formatter setDecimalSeparator:#"."];

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"?

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];

NSNumberFormatter to add and remove decimals

what is the best way on how to deal with integers, NSStrings and NSNumberFormatter ?
I have an app with an UITextField, where users can input numbers. By every change in the UITextField, my app is immediately taking the input, put it in my function that makes a calculation, and outputs the result in an UILabel.
people can work with large numbers here, so in order to make it easier for them to read what their input is, I decided that I want to make it possible so that the input changes as soon as they insert it.
For example, when you type in 1000 that it automatically changes into 1,000. when you type in 100000000000 it automatically changes into 100,000,000,000 etc.
This I was able to do myself, like this:
formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
self.inputField.text = [formatter stringFromNumber:[formatter numberFromString:self.inputField.text]];
maybe not the best way, but it works.
my function expects an int as input, so up till 999 it's very easy: i can do the following:
[self.inputField.text integerValue];
and it works
but whenever I have 1000 or higher in my UITextField, self.inputField.text property will be 1,000 .. and then things go wrong with using the integerValue from it.
So my question is, how can I go back from NSString to an int, when there are decimals in it ?
Use the -numberFromString function to get an NSNumber from the string, then use the intValue from the NSNumber class to get the integer value:
NSString *string = #"1,000";
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *number = [formatter numberFromString:string];
int intValue = [number integerValue];// intValue = 1000

"isnan" doesn't seem to work

Simply trying to catch non numeric input
Read MANY items . Tried decimalDigitCharacterSet (found it hard to believe that something that starts with the word "decimal" doesn't contain a decimal). Tried mutable character set to add the decimal. Been working to include "10.5" with "96" and still exclude "abc".
the following code produces "IS a number" no matter what I put in textbox1
double whatTheHey;
whatTheHey = _textBox1.text.doubleValue;
if isnan(whatTheHey) {
_textBox2.text = #"NOT a number > ";
}
if (!isnan(whatTheHey)) {
_textBox2.text = #"IS a number > ";
}
10.5 , 99 , qwerty all yield "IS a number"
This seems like a heck of a lot of work just to catch non numeric input.
Does anybody have any blatantky simple examples of working code to catch non numeric but accept numbers with decimal in them?
NaN does not literally mean "anything that is not a number". It is the name of a specific value — namely one floats can have after certain indeterminate operations such as dividing zero by zero or taking the square root of a negative number. See the Wikipedia entry for more history.
To actually parse the numeric value of a string, you probably want to look into NSNumberFormatter:
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *a = [numberFormatter numberFromString:#"10.5"];
NSNumber *b = [numberFormatter numberFromString:#"96"];
NSNumber *c = [numberFormatter numberFromString:#"abc"];
NSLog(#"a: %#, b: %#, c: %#", a, b, c);
Yields:
a: 10.5, b: 96, c: (null)
A simpler (if less flexible) solution that meets your specific criteria might be:
BOOL isNumber(NSString *aString){
return [aString integerValue] || [aString floatValue];
}
But if you're writing for iOS (or OS X), you really ought to get comfortable with the NSFormatters. They'll make your life a lot easier.
to check wether a string is numeric or not use the following piece of code.
NSString *newString = #"11111";
NSNumberFormatter *nf = [NSNumberFormatter new];
BOOL isDecimal = [nf numberFromString:newString] != nil;
Try this. I think it should do what you need:
- (BOOL)isStringNumeric:(NSString *)input {
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
NSNumber *number = [numberFormatter numberFromString:input];
return (number != nil);
}

Resources