Quick tip about localizing currency on iOS

[UPDATE:2014-02-19 I've modified this sample code. This worked in 2011, but not in 2014. I think the issue is that ARC used to make a copy in the call that creates the NSMutableCharacterSet but now it does not and you have to specify mutableCopy or you don't get a NSMutableCharacterSet. Where I once wrote:
NSMutableCharacterSet* tempSet = [NSCharacterSet whitespaceCharacterSet];
You should in fact use:
NSMutableCharacterSet* tempSet = [[NSCharacterSet whitespaceCharacterSet] mutableCopy];
I apologize for the confusion.

Let's say you have a text field in your iOS app and you want to take currency values in said field. NSNumberFormatter is your friend and can happily turn a string like "$42.23" into the floating point number 42.23. It will also turn the floating point number 42.23 back in "$42.23". Even better with the German locale active it will turn 42.23 into "$42,23 €" and vice-versa (note the comma as well as the euro symbol). Sweet! However, here's a minor glitch. Sweden's currency "symbol" is in fact a string – "kr". While your formatter will turn the float 42.23 into "42,23 kr" it cannot turn "42,23 kr" back into the floating point value. What to do? What I decided to do was strip whitespace and currency symbols from the string before trying to convert the string into a float. Like so:

NSCharacterSet* costTrimmingCharacters = nil;
//OK, some settings have currency symbols that can't survive a 2-way trip. For example, Sweden's currency "symbol" is "kr"
//So what we're going to do is trim whitespace and currency symbols from the string. Also then we don't have to use the currencyFormatter and can
//simply use the decimalFormatter (since it will strip $ from US locales, for example.)
NSMutableCharacterSet* tempSet = [[NSCharacterSet whitespaceCharacterSet] mutableCopy];
[tempSet addCharactersInString:[[NSLocale autoupdatingCurrentLocale] objectForKey:NSLocaleCurrencySymbol]];
costTrimmingCharacters = [tempSet copy];
//Note in a real app you should store costTrimmingCharacters somewhere and only build it the first time you need it.

NSNumberFormatter* currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setLocale:[NSLocale autoupdatingCurrentLocale];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSString* aggravatingString = [NSString stringFromString:@"42,23 kr"] NSString* goodString = [aggravatingString stringByTrimmingCharactersInSet:costTrimmingCharacters]; NSNumber* goodValue = [currencyFormatter numberFromString:goodString]


Full disclosure: I didn't test that exact snippet, it's frankensteined from a few pieces of code out of RoadTrip that would have just obscured the point. So there may be a syntax error somewhere due to a typo but the idea should be clear. Last two little suggestions:
  1. I use a related character set in the field delegate's shouldChangeCharactersInRange: replacementString: method so that I don't even accept illegal characters and that way you can't even enter "kr" unless you're in the Sweden locale.
  2. In the delegate's textFieldDidEndEditing: method once I've converted the string into a float I go right ahead and convert it back into a string and assign it back into the field. That means if they entered 42.23 they'll see a nice $42.23 or 42,23 € or whatever their locale specifies.