1

iPhone/Objective-C/Cocoa初心者はこちら。stackoverflow に関する多数の投稿に基づいて、私が構築している基本的な iPhone 電卓アプリで使用している IBAction をまとめました。IBAction はテンキーと連携して、小数点を入力せずに 10 進数を入力できるようにします。

「通貨を扱うときは 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 コード セグメントは float を使用し、currencyField2 セグメントは NSDecimal を使用します。

currencyField1 セグメントは希望どおりに機能します。小数点以下 2 桁のすべての数値を表示します (入力されたすべての数字を削除するために削除キーが使用されている場合でも)。ただし、大きな通貨値を処理するときに浮動小数点数を使用する場合の問題を完全に示しています。入力された数値が 8 桁を超えると、丸めエラーが発生します。

currencyField2 セグメントは、float の代わりに NSDecimal を使用することで、丸め誤差の問題を回避します。ただし、常に小数点以下 2 桁の数字が表示されるとは限りません。これは、入力されたすべての数字を削除するために削除キーが使用された場合に表示されます。問題は次のコード行によるものだと思います。

currencyField2.text = [@"" stringByAppendingFormat:@"%@", currency2];

これは、float の目的の形式を生成する次の行の結果です。

currencyField1.text = [@"" stringByAppendingFormat:@"%0.2f", currency];

したがって、「0」値 NSDecimalNumber の表示をフォーマットするには、@"%0.2f" に相当するものが必要だと思います。私は恥ずかしいほど何時間もこれに取り組んできましたが、それを理解することはできません.

ヘルプやポインタをいただければ幸いです。

編集: 問題を解決したと思われる NSNumberFormatter オブジェクト (ブラッドがコメントで説明したものと同様) を組み込みました。ただし、コードが機能するようになったので、コードのリファクタリングについてフィードバックをお願いします。改訂されたコードは次のとおりです。

// 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

それは私の最初の問題に対処しますが、それを改善する方法についてアドバイスをいただければ幸いです。ありがとう。

4

2 に答える 2

1

テキスト値の小数点以下 2 桁を保証する場合は、次のコードのように NSNumberFormatter を使用できます (こちらの回答から抜粋)。

NSNumberFormatter *decimalNumberFormatter = [[NSNumberFormatter alloc] init];
[decimalNumberFormatter setMinimumFractionDigits:2];
[decimalNumberFormatter setMaximumFractionDigits:2];
currencyField2.text = [decimalNumberFormatter stringFromNumber:currency2];
[decimalNumberFormatter release];

これにより、NSDecimalNumber の精度が維持されるはずです。個人的には、パフォーマンス上の理由から NSDecimal C 構造体を使用することを好みますが、値を出し入れするのが少し難しくなります。

于 2010-01-03T04:41:38.247 に答える
0

-setFormat:NSNumberFormatter の代わりに (NSNumberFormatter の) メソッドを使用できませんか? 目的に合わせて構成できるはずであり、通貨でフォーマットされた文字列の奇妙な「ハック」に対処する必要はないようです。

詳細については、次を参照してください。

于 2011-08-26T06:13:40.417 に答える