核心数据以精确度存储NSDecimalNumber

时间:2013-11-13 15:19:35

标签: ios core-data

我正在接收并解析JSON并将数据存储到Core Data中。某些数据是存储为NSDecimalNumber的货币,但其中一些值的精度高于两位小数。

例如,如果我从服务中获取一个值,例如8.2399999995,我想将其作为8.24存储在Core Data中。有没有办法将我的模型设置为两位小数精度?或者我需要在存储后手动舍入每个值?

更新

Leijonien感谢您提供的信息。我试图这样做,我在保存格式化值时遇到了一些麻烦。我检查了JSON并搜索了Google,结果发现我从服务中获得了一个干净的价值。 RESTKit就是问题.... https://github.com/RestKit/RestKit/issues/1405

但是,我在我的一个NSManagedObject类上创建了一个类别,覆盖了我想要的属性的setter,格式化了值,但我仍然看到我的db中的长十进制值。这是我的代码。

- (void)setAmount:(NSDecimalNumber *)amount {
    NSDecimalNumberHandler *round = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
                                                                                           scale:2
                                                                                raiseOnExactness:NO
                                                                                 raiseOnOverflow:NO
                                                                                raiseOnUnderflow:NO
                                                                             raiseOnDivideByZero:YES];
    NSDecimalNumber *newAmount = [amount decimalNumberByRoundingAccordingToBehavior:round];
    NSLog(@"%@", newAmount);
    [self setPrimitiveValue:newAmount forKey:@"amount"];
}

奇怪的是,当newAmount打印到控制台时,它的格式为8.24,就像我想要的那样,但当我检查数据库时,它保存为8.2399999995。我在这里做错了吗?

3 个答案:

答案 0 :(得分:2)

CoreData将只存储您传递的值,因此如果您只需要2位数,则应自行舍入该值。可能更好地在存储之前对值进行舍入,因此每个结果只需要执行一次。

答案 1 :(得分:1)

事实证明,问题不在于RESTKit。事实上,问题似乎是核心数据。这就是为什么在我的setter方法中打印到控制台打印正确格式化的数字,但数字在db中具有错误的精度。对于这种情况,最好的补救方法是在从Core Data中提取后,覆盖getter方法并格式化那里的数字。以下似乎有效...如果您发现其他任何有用的东西,请告诉我。

- (NSDecimalNumber*)amount {
    [self willAccessValueForKey:@"amount"];
    NSDecimalNumber* unroundedAmount = [self primitiveValueForKey:@"amount"];
    [self didAccessValueForKey:@"amount"];

    NSDecimalNumberHandler *round = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
                                                                                           scale:2
                                                                                raiseOnExactness:NO
                                                                                 raiseOnOverflow:NO
                                                                                raiseOnUnderflow:NO
                                                                             raiseOnDivideByZero:YES];
    NSDecimalNumber *roundedAmount = [unroundedAmount decimalNumberByRoundingAccordingToBehavior:round];

    return roundedAmount;
}

答案 2 :(得分:1)

有一点需要注意的是,一些(大多数?)十进制数字不能以与我们想象的完全相同的方式存储在浮点二进制数中。有很多东西可以在那里阅读,但我喜欢这个的详细方法:http://www.cprogramming.com/tutorial/floating_point/understanding_floating_point_representation.html

因此,对于您的数字, .24 不能以浮点表示,因为二进制只能表示数字的小数部分由组成。 5,.25,.125,...... (可能缺少一些特殊规则,但这是一般的想法)。因此,要表示 .24 ,它会使用尽可能多的较低值来尽可能接近。

NSDecimalNumber已经设置为围绕它,但是如果你不告诉它四舍五入,你也会看到相同的 8.23999 ... 值。