Как выполнить точный расчет валюты в приложении для iPhone - PullRequest
1 голос
/ 04 декабря 2009

Я написал приложение для iPhone, которое вычисляет общую стоимость, добавляя / вычитая единицы заданной стоимости. Это работало нормально, пока я не понял, что значения с плавающей точкой, которые я использовал, приводили к неточности итогового значения, поэтому я начал изучать использование NSDecimalNumber. Я сейчас немного сбит с толку и у меня ошибка «вне области видимости». Соответствующие разделы моего (упрощенного) кода приведены ниже. Как я могу заставить это работать как ожидалось?

MyViewController.h

#import <UIKit/UIKit.h>

@interface MyViewController : UIViewController {
    IBOutlet UILabel *totalPrice;
    NSDecimalNumber *total;
    NSDecimalNumber *item1Price;
}

@property (retain, nonatomic) NSDecimalNumber *total;
@property (retain, nonatomic) UILabel *totalPrice;

- (IBAction)addItem:(id)sender;
- (void)getDefaults;
- (void)setLabels;
@end

MyViewController.m

#import "MyViewController.h"

@implementation MyViewController

@synthesize total;
@synthesize totalPrice;

- (void)getDefaults {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"prices" ofType:@"plist"];
    NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
    total = [NSDecimalNumber decimalNumberWithString:@"0"];
    item1Price = (NSDecimalNumber *)[dict valueForKey:@"item1"];
}

- (void)setLabels {
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
    [numberFormatter setCurrencySymbol:@"£"];
    [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    totalPrice.text = [numberFormatter stringFromNumber:total];
}

- (void)viewDidLoad {
    [self getDefaults];
    [self setLabels];
}

- (IBAction)addItem:(id)sender {
    NSDecimalNumber *itemPrice;

    switch ([sender tag]) {
        case 1:
            itemPrice = item1Price;
            break;
    }

    total = [total decimalNumberByAdding:itemPrice];

    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
    [numberFormatter setCurrencySymbol:@"£"];
    [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

    totalPrice.text = [numberFormatter stringFromNumber:total];
}

@end

Я надеюсь, что я на правильном пути ...

Ответы [ 3 ]

1 голос
/ 04 декабря 2009


Ваша ошибка вне области видимости может объясняться тем фактом, что 'total' и 'itemPrice1' определены как переменная экземпляра и используются как таковые, то есть вы используете их в классе. Метод getDefaults устанавливает их значения, которые затем используются в других методах. Однако, инициализируя эти переменные как:

 total = [NSDecimalNumber decimalNumberWithString:@"0"];
item1Price = (NSDecimalNumber *)[dict valueForKey:@"item1"];

... они автоматически выпускаются в конце этого метода (в этой области). У вас есть два варианта инициализации:

total = [[NSDecimalNumber decimalNumberWithString:@"0"] retain];
// OR
total = [[NSNumber alloc] initWithString:@"0"];

Независимо от того, какой вариант вы выберете из вышеперечисленных, вам придется выпустить его позже (обычно в методе dealloc класса).

Не уверен, что проблема была в использовании NSNumber. Вы упомянули, что float недостаточно точен, и в этом случае я бы просто использовал double. Вы могли бы сделать это:

double totalSetter = 0.0;
NSNumber *total = [[NSNumber alloc] initWithDouble:totalCaster];

, а затем получить с помощью:

double totalGetter = [total doubleValue];

Теперь вы должны иметь возможность использовать NSNumberFormatter с вашими NSNumbers.

1 голос
/ 04 декабря 2009

Вы можете использовать целые числа для вычисления, просто умножив дробную часть и разделив, чтобы вернуться к правильному значению.

В противном случае вы можете попробовать использовать удвоение, это то, что фактически используется для большинства типов данных SDK, требующих точности (например, CLLocationCoordinate, NSTimeInterval).

0 голосов
/ 07 декабря 2009

Здесь было два вопроса. Одной из них была ошибка области действия, которую я решил, используя команду retain, предложенную imnk. Я уже попробовал это, но мой decimalNumberByAdding дал неточные результаты.

Оказывается, что несмотря на установку itemPrice1 в качестве NSDecimalNumber строки:

item1Price = (NSDecimalNumber *)[dict valueForKey:@"item1"];

менял его на NSCFNumber. Чтобы решить эту проблему, я изменил эту переменную на NSString и создал NSDecimalNumber из строки, чтобы использовать ее в моем методе.

...