iPhone 使用 NSDecimal 代替 float 进行货币输入
iPhone/Objective-C/Cocoa 新手在这里。根据 stackoverflow 上的许多帖子,我拼凑了一个 IBAction,我正在构建一个基本的 iPhone 计算器应用程序中使用它。 IBAction 与数字键盘配合使用,允许输入十进制数字,而无需输入小数点。
我正在努力遵守“处理货币时使用 NSDecimal”的格言,尽管我发现很难像许多其他提出问题的人那样做到这一点。我正在稳步取得进展,但遇到了困难,在我了解 NSDecimal 和格式规范后,我确信这看起来微不足道。
这是我正在使用的 IBAction(它是由编辑更改的 UITextField 事件触发的):
// called when user touches a key or button
- (IBAction)processKeystrokes:(id)sender
{
static BOOL toggle = YES; // was this method triggered by the user?
// the user touched the keypad
if (toggle)
{
toggle = NO;
// retrieve the strings in input fields
NSString *currencyField1Text = currencyField1.text;
NSString *currencyField2Text = currencyField2.text;
if (sender == currencyField1) {
currencyField1Text = [currencyField1Text stringByReplacingOccurrencesOfString:@"." withString:@""];
float currency = [currencyFieldText floatValue]/100;
currencyField1.text = [@"" stringByAppendingFormat:@"%0.2f", currency];
}
else if (sender == currencyField2) {
currencyField2Text = [currencyField2Text stringByReplacingOccurrencesOfString:@"." withString:@""];
NSDecimalNumber *currency2 = [[NSDecimalNumber decimalNumberWithString:currencyField2Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]];
currencyField2.text = [@"" stringByAppendingFormat:@"%@", currency2];
}
else {
NSLog(@"Some unexpected input");
}
}
else
{
toggle = YES;
}
} // end method calculateResults
currencyField1 代码段使用浮点数,currencyField2 段使用 NSDecimal。
currencyField1 段按预期工作:显示小数点后两位数字的所有数字(即使使用删除键删除所有输入的数字);然而,它遇到并完美地说明了在处理大货币值时使用浮点数的问题:当输入的数字超过 8 位时,会出现舍入错误。
currencyField2段通过使用NSDecimal而不是float来避免舍入错误问题;然而,它并不总是显示小数点后两位数字——当使用删除键删除所有输入的数字时,会显示这种情况。我相信问题是由于这行代码造成的:
currencyField2.text = [@"" stringByAppendingFormat:@"%@", currency2];
这是生成所需的浮点格式的以下行的推论:
currencyField1.text = [@"" stringByAppendingFormat:@"%0.2f", currency];
因此,我认为我需要相当于 @"%0.2f" 来格式化 " 的显示0”值 NSDecimalNumber。我已经在这个问题上呆了好几个小时了,我感到很尴尬,但我就是不明白。
任何帮助或指示表示赞赏。
编辑:我合并了 NSNumberFormatter 对象(类似于 Brad 在他的评论中描述的内容),这似乎已经解决了问题。但是,现在我已经可以使用代码了,我希望获得一些关于重构代码的反馈。这是修改后的代码:
// called when user touches a key or button
- (IBAction)processKeystrokes:(id)sender
{
static BOOL toggle = YES; // was this method triggered by the user?
// the user touched the keypad
if (toggle)
{
toggle = NO;
// retrieve the strings in input fields
NSString *currencyField1Text = currencyField1.text;
NSString *currencyField2Text = currencyField2.text;
// new code elements
NSNumberFormatter * nf = [[[NSNumberFormatter alloc] init]autorelease];
[nf setNumberStyle:NSNumberFormatterCurrencyStyle];
[nf setCurrencySymbol:@""];
[nf setCurrencyGroupingSeparator:@""];
if (sender == currencyField1) {
currencyField1Text = [currencyField1Text stringByReplacingOccurrencesOfString:@"." withString:@""];
NSDecimalNumber *currency = [[NSDecimalNumber decimalNumberWithString:currencyField1Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]];
currencyField1.text = [nf stringFromNumber:currency];
}
else if (sender == currencyField2) {
currencyField2Text = [currencyField2Text stringByReplacingOccurrencesOfString:@"." withString:@""];
NSDecimalNumber *currency2 = [[NSDecimalNumber decimalNumberWithString:currencyField2Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]];
currencyField2.text = [nf stringFromNumber:currency2];
}
else {
NSLog(@"Some unexpected input");
}
}
else
{
toggle = YES;
}
} // end method calculateResults
它解决了我最初的问题,但我将不胜感激任何有关如何改进它的建议。谢谢。
iPhone/Objective-C/Cocoa newbie here. Based on a number of posts on stackoverflow, I have cobbled together an IBAction that I'm using in a basic iPhone calculator app that I'm building. The IBAction works with the numeric keypad to allow entry of decimal numbers without having to enter a decimal point.
I am trying very hard to adhere to the "use NSDecimal when dealing with currency" adage although I am finding it difficult to do so like so many others who have posted questions. I am making steady progress, but have hit a wall that I'm sure will look trivial after I get my head around NSDecimal and Format Specifications.
Here is the IBAction I'm using (it is triggered by Editing Changed UITextField Event):
// called when user touches a key or button
- (IBAction)processKeystrokes:(id)sender
{
static BOOL toggle = YES; // was this method triggered by the user?
// the user touched the keypad
if (toggle)
{
toggle = NO;
// retrieve the strings in input fields
NSString *currencyField1Text = currencyField1.text;
NSString *currencyField2Text = currencyField2.text;
if (sender == currencyField1) {
currencyField1Text = [currencyField1Text stringByReplacingOccurrencesOfString:@"." withString:@""];
float currency = [currencyFieldText floatValue]/100;
currencyField1.text = [@"" stringByAppendingFormat:@"%0.2f", currency];
}
else if (sender == currencyField2) {
currencyField2Text = [currencyField2Text stringByReplacingOccurrencesOfString:@"." withString:@""];
NSDecimalNumber *currency2 = [[NSDecimalNumber decimalNumberWithString:currencyField2Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]];
currencyField2.text = [@"" stringByAppendingFormat:@"%@", currency2];
}
else {
NSLog(@"Some unexpected input");
}
}
else
{
toggle = YES;
}
} // end method calculateResults
The currencyField1 code segment uses floats, the currencyField2 segment uses NSDecimal.
The currencyField1 segment works as desired: displays all numbers with two digits after the decimal point (even when the delete key is used to delete all entered digits); however it suffers from and illustrates perfectly the problem with using floats when dealing with large currency values: rounding errors show up when entered numbers exceed 8 digits.
The currencyField2 segment avoids rounding error problem by using NSDecimal instead of float; however it does not always display numbers with two digits after the decimal point -- this is shown when the delete key is used to delete all entered digits. I believe the problem is due to this line of code:
currencyField2.text = [@"" stringByAppendingFormat:@"%@", currency2];
This is the corollary to the following line that produces the desired format for floats:
currencyField1.text = [@"" stringByAppendingFormat:@"%0.2f", currency];
So, I think I need the equivalent of @"%0.2f" for formatting the display of a "0" value NSDecimalNumber. I have been at this for so many hours that I'm embarrassed, but I just can't figure it out.
Any help or pointers are appreciated.
EDIT: I incorporated the NSNumberFormatter object (similar to what Brad describes in his comment) which seems to have solved the problem. However, I would like some feedback on refactoring the code now that I have it working. Here's the revised code:
// called when user touches a key or button
- (IBAction)processKeystrokes:(id)sender
{
static BOOL toggle = YES; // was this method triggered by the user?
// the user touched the keypad
if (toggle)
{
toggle = NO;
// retrieve the strings in input fields
NSString *currencyField1Text = currencyField1.text;
NSString *currencyField2Text = currencyField2.text;
// new code elements
NSNumberFormatter * nf = [[[NSNumberFormatter alloc] init]autorelease];
[nf setNumberStyle:NSNumberFormatterCurrencyStyle];
[nf setCurrencySymbol:@""];
[nf setCurrencyGroupingSeparator:@""];
if (sender == currencyField1) {
currencyField1Text = [currencyField1Text stringByReplacingOccurrencesOfString:@"." withString:@""];
NSDecimalNumber *currency = [[NSDecimalNumber decimalNumberWithString:currencyField1Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]];
currencyField1.text = [nf stringFromNumber:currency];
}
else if (sender == currencyField2) {
currencyField2Text = [currencyField2Text stringByReplacingOccurrencesOfString:@"." withString:@""];
NSDecimalNumber *currency2 = [[NSDecimalNumber decimalNumberWithString:currencyField2Text] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"100"]];
currencyField2.text = [nf stringFromNumber:currency2];
}
else {
NSLog(@"Some unexpected input");
}
}
else
{
toggle = YES;
}
} // end method calculateResults
It addresses my initial problem, but I would appreciate any advice on how to improve it. Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您想保证文本值小数点后有 2 位数字,您可以使用 NSNumberFormatter,如以下代码所示(取自答案 此处):
我相信这应该保留 NSDecimalNumber 的精度。就我个人而言,出于性能原因,我更喜欢使用 NSDecimal C 结构,但这有点难以传入和传出值。
If you want to guarantee 2 digits after the decimal point for your text value, you could use an NSNumberFormatter like in the following code (drawn from the answer here):
I believe this should preserve the precision of the NSDecimalNumber. Personally, I prefer to use the NSDecimal C struct for performance reasons, but that's a little harder to get values into and out of.
您不能使用(NSNumberFormatter 的)
-setFormat:
方法来代替 NSNumberFormatter 吗?似乎人们应该能够根据您的目的配置它,并且您不必处理货币格式字符串上的奇怪“黑客”。有关详细信息,请参阅:
-setFormat
的文档Can't you use the
-setFormat:
method (of NSNumberFormatter) instead for the NSNumberFormatter? Seems one should be able to configure it for your purposes and you wouldn't have to deal with weird "hacks" on a currency formatted string.For more info see:
-setFormat