Reputation: 185
My app uses monetary values, and I would like to represent these values in the currency and formats that the user has set on their iPhone however, when testing, I seem to be having troubles with the German EURO format.
I have a method that returns a decimal number (for storing in core data) from the currency formatted string. The string was actually formatted by another (similar) method using NSlocale.
I have tested with UK, US, Japanese and German locales, so far only Germany has caused any problems.
Here's the code, the string being passed is for example: 2,56 €
+ (NSDecimalNumber*)TLCurrencyFormatFromString:(NSString*)strNumber {
NSNumberFormatter *fmtrCurrencyFromStr = nil;
fmtrCurrencyFromStr = [[NSNumberFormatter alloc] init];
[fmtrCurrencyFromStr setFormatterBehavior:NSNumberFormatterBehavior10_4];
[fmtrCurrencyFromStr setLocale:[NSLocale currentLocale]];
[fmtrCurrencyFromStr setNumberStyle:NSNumberFormatterCurrencyStyle];
[fmtrCurrencyFromStr setGeneratesDecimalNumbers:YES];
NSLog(@"Currency Separator: %@", [fmtrCurrencyFromStr decimalSeparator]); //prints a comma
NSLog(@"Currency Code: %@", [fmtrCurrencyFromStr currencyCode]); //prints EUR
int currencyScale = [fmtrCurrencyFromStr maximumFractionDigits];
NSDecimalNumberHandler *roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:currencyScale raiseOnExactness:FALSE raiseOnOverflow:TRUE raiseOnUnderflow:TRUE raiseOnDivideByZero:TRUE];
NSDecimalNumber* currencyNumber = [[NSDecimalNumber alloc] initWithDecimal:[[fmtrCurrencyFromStr numberFromString:strNumber] decimalValue]];
NSLog(@"Currency Number = %@", [currencyNumber decimalNumberByRoundingAccordingToBehavior:roundingBehavior]);
return [currencyNumber decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
}
The 'currencyNumber' variable gets printed as: -18446912453607470532000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
whereas in all the other locales, it would print 2.56 for storing into Core Data as NSDecimalNumber.
Upvotes: 0
Views: 1248
Reputation: 1823
I verified that on iOS 4.3 using the [formatter setLenient:YES] flag worked for me as well using Euros. Without that flag set, the formatter does not return correct values for Euros.
Upvotes: 0
Reputation: 185
Setting the property:
[fmtrCurrencyFromStr setLenient:YES];
Fixes the problem for France, Germany, Norway, UK, US, Japan, Nambia etc... I can't say it fixes it for all because I haven't tested all, but of all those that I've tested so far, it has worked.
Upvotes: 2
Reputation: 33592
I think your problem is with the line
NSDecimalNumber* currencyNumber = [[NSDecimalNumber alloc] initWithDecimal:[[fmtrCurrencyFromStr numberFromString:strNumber] decimalValue]];
Try replacing it with the mostly-equivalent line
NSDecimalNumber * currencyNumber = [fmtrCurrencyFromStr numberFromString:strNumber];
You've set generatesDecimalNumbers
, so the two are pretty much equivalent except for one annoying case: nil.
Sending a message to nil is guaranteed to do nothing and return 0 for most standard types (integer (except not 64-bit integers on old 32-bit runtimes), floating point, pointer types); it "returns" uninitialized memory if the method returns a struct. NSDecimal is a struct.
(The underlying reason is essentially that the runtime doesn't know how big the struct is, so doesn't know how much memory to zero, hence you get "uninitialized" memory instead. I usually hit this one when I do v.frame
without ensuring that v is not nil.)
EDIT: Of course, you other problem is why NSNumberFormatter isn't parsing the price correctly. That's a tough one. I'd try stripping the currency symbol.
Upvotes: 0