【问题标题】:Do I really need to convert my project currency to NSDecimalNumber?我真的需要将我的项目货币转换为 NSDecimalNumber 吗?
【发布时间】:2015-10-02 03:34:10
【问题描述】:

是的,我知道我应该使用NSDecimalNumber 来处理货币、金钱、价格...I've read this. 问题是,我改编了一个现有项目,它使用NSStringNSNumber (float , double, CGFloat...) 作为货币。他们使用NSNumberFormatter 处理浮点数,我可以看到这不是一个大问题(还没有?)。这些货币存储在 coredata 中。

现在,如果我想将所有这些货币转换为NSDecimalNumber,我将不得不对代码进行大规模重构并迁移到 coredata。问题来了:

  1. 如果(我假设)doubleCGFloatNSNumber 可以保持与NSDecimalNumber 一样大的值,我为什么要使用NSDecimalNumber,因为我可以使用 其他NSNumberFormatter?是因为性能吗?

  2. 如果需要转换,我是否可以仅借助 MappingModel 进行自动迁移,当然),或者我有 调整自定义迁移策略?

因为 coredata 使用 NSStringNSNumber 作为货币,所以请帮我找到从这两种数据类型迁移的解决方案。我不习惯在 coredata 中使用NSDecimalNumber。提前致谢。

编辑

好的,我知道 NSDecimalNumber 是必要的。请帮我回答第二个问题:我可以使用mappingModel + FUNCTION($source.price, "decimalValue") 之类的东西进行自动迁移(这是不正确的,因为decimalValue 返回NSDecimal,而不是NSDecimalNumber)。我真的需要编写自定义迁移策略吗?

【问题讨论】:

    标签: ios objective-c core-data currency core-data-migration


    【解决方案1】:

    我真的需要编写自定义迁移策略吗?

    是的。为每个需要转换的实体创建一个 NSEntityMigrationPolicy 的子类,并实现方法 createDestinationInstancesForSourceInstance:entityMapping:manager:error:。在映射模型中实体的自定义策略中输入该类的名称。

    - (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance
        entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager
        error:(NSError **)error
    {
        BOOL aBool = [super createDestinationInstancesForSourceInstance:sInstance entityMapping:mapping manager:manager error:error];
        if (aBool)
        {
            NSArray *aSourceArray = [[NSArray alloc] initWithObjects:&sInstance count:1];
            NSArray *aDestArray = [manager destinationInstancesForEntityMappingNamed:[mapping name] sourceInstances:aSourceArray];
            if (aDestArray && [aDestArray count] > 0)
            {
                NSManagedObject *dInstance = [aDestArray objectAtIndex:0];
                // conversion
            }
        }
        return aBool;
    }
    

    【讨论】:

    • 您好,谢谢您的回答。如果我只能为所有需要转换的实体编写一个自定义策略,我可以吗?我想我可以,但问题是我不知道何时执行转换(NSStringNSNumberNSDecimalNumber)。我可以查看destinationInstance中的房产等级吗?
    • 您可以对所有实体使用相同的迁移策略,但如果键不同,您必须检查每个托管对象的实体名称。可以查看sInstance中属性的类,dInstance中的属性为nil。
    • 谢谢,我设法为我需要的所有实体创建了 1 个策略。尽管迁移代码可能看起来很难看,但它按预期工作。
    【解决方案2】:

    问题在于doubleCGFloat 以及存储在NSNumber 中的那些值类型无法精确处理十进制值。因此,如果您设置 4.50,您最终可能会得到一些接近的近似值。这对于货币价值通常是不可取的,因为您需要精确的表示。您或许可以使用 NSNumberFormatter 进行四舍五入,但如果您开始使用这些值进行数学运算或需要比百分之一更高的精度,则最终可能会得到不正确的数量。

    我怀疑您必须进行大规模迁移才能更改 CoreData 实体上的属性类型。即使您不必这样做,您也可能希望这样做,这样您就可以确保转换为 Decimal 的值被四舍五入到您选择的精度(因为它们可能是也可能不是您在数据库中想要的正确现在)。

    听起来您的项目中有一些技术债务。您是选择现在偿还债务还是等到债务增长最终取决于您。

    【讨论】:

    • 感谢您的回答。但我不想进行大量迁移,因为它可能非常复杂。我可以在映射模型中写一些东西吗?想转换 NSNumber,我会写 FUNCTION($source.price, "decimalValue")。但是 NSString 呢?我自己也不确定。你能帮我解决这个问题吗?
    • 我对映射模型不是很熟悉,但NSDecimalNumber 确实有一个采用String 类型的init 方法。我要补充一点,将货币价值数字存储为String 是可以的(尽管数据库中String 占用的空间大于Decimal)。如果您愿意,可以继续将它们存储为Strings,并在需要使用它们时在代码中创建NSDecimalNumber 值。真正的问题是像double/float这样的非精确类型。
    【解决方案3】:

    您可能想使用NSDecimalNumber,而不是NSDecimalNSDecimalstruct,而 NSDecimalNumber 是继承自 NSNumber 的 Objective-C 类。因此,您通常可以在任何接受NSNumber 的地方传递NSDecimalNumberNSNumberFormatter 自动格式化NSDecimalNumber 实例,如果你将格式化程序的generatesDecimalNumbers 设置为YES,它会将字符串解析为NSDecimalNumber 实例。

    NSDecimalNSDecimalNumber 的范围大于doubleCGFloat。十进制类型存储更多有效数字并具有更大的指数范围。

    我不知道自动迁移问题的答案,但我知道 Core Data 支持NSDecimalNumber。您可以在模型中将属性的类型设置为十进制 (NSDecimalAttributeType)。

    【讨论】:

    • 谢谢,我知道我对 NSDecimalNSDecimalNumber 的看法是错误的。第二部分(关于迁移)比第一部分更重要。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    相关资源
    最近更新 更多