I found this to be a relatively clean approach. I haven't tested it with non-US currencies but since it uses the NSNumberFormatter's properties I believe it should handle them correctly.
Start by setting up a formatter some place:
formatter = [NSNumberFormatter new];
[formatter setNumberStyle: NSNumberFormatterCurrencyStyle];
[formatter setLenient:YES];
[formatter setGeneratesDecimalNumbers:YES];
Use the formatter to parse and reformat their input. It also handles shifting the number when digits are added and removed.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *replaced = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSDecimalNumber *amount = (NSDecimalNumber*) [formatter numberFromString:replaced];
if (amount == nil) {
// Something screwed up the parsing. Probably an alpha character.
return NO;
}
// If the field is empty (the initial case) the number should be shifted to
// start in the right most decimal place.
short powerOf10 = 0;
if ([textField.text isEqualToString:@""]) {
powerOf10 = -formatter.maximumFractionDigits;
}
// If the edit point is to the right of the decimal point we need to do
// some shifting.
else if (range.location + formatter.maximumFractionDigits >= textField.text.length) {
// If there's a range of text selected, it'll delete part of the number
// so shift it back to the right.
if (range.length) {
powerOf10 = -range.length;
}
// Otherwise they're adding this many characters so shift left.
else {
powerOf10 = [string length];
}
}
amount = [amount decimalNumberByMultiplyingByPowerOf10:powerOf10];
// Replace the value and then cancel this change.
textField.text = [formatter stringFromNumber:amount];
return NO;
}