NSNumberFormatter numberFromString returns 0 for currency style formatter

3k Views Asked by At

I tried to test the following code in order to get a double value from a currency-style formatted UITextField (ex : $ 30,034.12 => 30034.12) :

// Init and configure formatter
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatter setMaximumFractionDigits:2];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"us_US"];
[formatter setLocale:locale];
[formatter setGroupingSize:3];
[formatter setUsesGroupingSeparator:YES];
[formatter setGroupingSeparator:@","];
[formatter setAllowsFloats:YES];

// Get a formatted string using the local currency formatter and then get a double
// vice-versa
NSNumber *amount = [NSNumber numberWithDouble:30034.12];

NSString *amountString = [formatter stringFromNumber:amount];
// Output here OK : @"$ 30,034.12"

double amountDouble = [[formatter numberFromString:amountString] doubleValue];
// Output here NOT OK : 0

Did anyone have/solved the same problem ?

Thanks !

Update :

@DanielBarden and the others. Actually to simplify the post I didn't include the part specifying where I got my string from : a text field. In fact, the line before the end of the code should be :

NSString *amountString = [textField text];

And this text field was previously formatted with following code from another method (currency style using the same formatter configuration) :

    // Init fromatter with style $ XXX,XXX.yy
    NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
    [formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    [formatter setMaximumFractionDigits:2];
    NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"us_US"];
    [formatter setLocale:locale];
    [formatter setGroupingSize:3];
    [formatter setGroupingSeparator:@","];
    [formatter setUsesGroupingSeparator:YES];

    // Get the float value of the text field and format it
    textField.text = [formatter 
                      stringFromNumber:[NSNumber 
                                        numberWithDouble:[textField.text 
                                                         floatValue]]];

Now the problem is that I get exactly the same strings when I do an NSLog but when I compare them char by char with a loop, it says that the space after the $ is a "real space" on the text field and differente symbol on the initial string (amountString the one I tried to test with in the initial post ...). Encoding issue ?

3

There are 3 best solutions below

1
PengOne On

The code appears correct to me and Xcode agreed with me. I added in two lines that you are missing:

NSLog(@"%@",amountString);
NSLog(@"%f",amountDouble);

and the output was correct. I suggest you check how you are logging the values.

1
A Salcedo On

The only thing that I can think of is the issue with the $ symbol. Setting up the formatter to currency style is expecting the $ symbol, and if it is not present on the string it returns 0

0
DawnSong On

The problem is formatter.currencySymbol might not be the correct one "$", which is "USD". So the solution is formatter.currencySymbol = "$"

let localeID = "th_TH" // Thailand
let correctCurrencySymbol = "฿" // "$" for US dollar
let formatter = NumberFormatter()
formatter.locale = Locale(identifier:localeID)
formatter.numberStyle = .currencyStyle
let currencySymbol = formatter.currencySymbol // "฿" for iOS 13, "THB" for iOS 12 or earlier versions
print("currencySymbol: \(currencySymbol)")

if (currencySymbol != correctCurrencySymbol) { // "USD" for US dollar
    formatter.currencySymbol = correctCurrencySymbol 
    print("【Error】fix formatter.currencySymbol from \(currencySymbol) to \(correctCurrencySymbol)")
}

let amount = -30.12
if let str = formatter.string(for: amount) {
   print("Currency format of \(amount) is \(str)") // -฿30.12
   // works OK until set correctCurrencySymbol
   if let amount1 = formatter.number(from: str)?.decimalValue {
       print("Comvert back to number is \(amount1)") // -30.12
   }
}