我应该如何在核心数据中存储从 UISlider 读取的百分比值?

Posted

技术标签:

【中文标题】我应该如何在核心数据中存储从 UISlider 读取的百分比值?【英文标题】:How should I store percentage values in Core Data that are read off UISliders? 【发布时间】:2010-12-23 18:27:21 【问题描述】:

滑块是我的应用程序的主要用户交互元素(看图...)。我使用它们记录百分比值,然后将其作为Readings 存储在我的核心数据存储中。根据百分比值的性质,我会将它们存储为 0 到 1 之间的十进制值,并将滑块设置为从 0 到 1 的范围,并连续触发它们的值更改动作。当我需要显示它们时,我从数据存储中获取它们并将它们显示为典型的百分比值,例如67%.

现在要注意了:UISlidervalue 属性是 float 类型。这意味着我会从一开始就遇到舍入错误。我非常注重准确性,所以我希望在整个应用程序中处理它们时尽可能地减少误差范围。

有哪些选项可用于管理我从滑块中读取的百分比值、存储在 Core Data 中并显示在我的应用程序的其余部分中?或者更好的是,就代码可维护性内存使用/性能准确性而言,我提出的这些选项中的哪一个最适合我的应用获得的值有多少

    使用原始浮点数或双精度数

    实际上这是BAD,显然是因为舍入错误。甚至 0.64 也会在某个时间点变成 0.63(我已经用我的滑块进行了测试,这些都出现了很多)。差异可能高达 0.01,我的应用程序绝对不能容忍这一点。为什么我还要写这个作为一个选项?

    将滑块范围设置为 0 到 100 之间,读取它们,向上/向下舍入并存储为整数

    这是一个有趣的选择,因为我只会将值显示为##% 而不是0.##。我也不需要对这些值进行算术运算,所以这样做看起来没问题:

    // Recording and storing
    // Slider range is 0 to 100
    int percentage = (int) floor(slider.value);             // Or ceil()
    [reading setValue:[NSNumber numberWithInt:percentage]]; // Value is an integer
    
    // Displaying
    NSNumber *val = reading.value;
    [readingLabel setText:[NSString stringWithFormat:@"%d%%", [val intValue]]];
    

    当我第一次从滑块上读取它们时,这不会完全消除舍入误差(它们仍然是 floats!),但我认为 floor()ceil() 应该消除它。不过,我并不完全确定;也许这里有人可以提供更多见解,这就是我提出这个问题的重点。

    转换并存储为NSDecimalNumber 对象

    我查看了NSDecimalNumber 类——毕竟百分比是基数为 10 的因子——但鉴于它产生不可变对象,我不太确定我是否喜欢编写长方法调用的想法重复我的代码并在各处创建大量自动释放的对象。

    即使是用原语创建NSDecimalNumbers 也是一种痛苦。目前我只能想到这样做:

    // Recording and storing
    // Slider range is 0 to 1
    NSDecimalNumber *decimalValue = [NSDecimalNumber decimalNumberWithString:
                                    [NSString stringWithFormat:@"%0.2f", 
                                        slider.value]];
    [reading setValue:decimalValue]; // Value is a decimal number
    

    将它们乘以 100,因为我将它们显示为 ##%(就像我上面所说的那样)也变得非常乏味并创建不必要的额外对象,然后将其转换为 NSStrings。我会继续说下去,但我可能会把这篇文章变成咆哮,这绝对不是我想要的。

    话虽如此,语义上NSDecimalNumber 应该是最有意义的,因为正如我上面所说,我相信百分比应该存储为 0 到 1 之间的十进制值。但是,看看我的应用如何处理百分比值,我不知道是选择将它们乘以 100 并存储为整数还是使用 NSDecimalNumber

您可能会看到我已经稍微倾向于第二个选项(x100,使用整数),因为它更方便并且看起来性能稍好一些。但是,我想看看是否有人认为第三个更好(更多的未来证明?)。

顺便说一句,我不介意修改我的数据模型以更改我的Reading 实体中value 属性的数据类型,并修改我现有的代码以适应这些更改。我还没有做太多,因为我把剩下的时间都花在了担心这件事上。

您认为我应该选择以上哪个选项?

【问题讨论】:

NSDecimalNumber 继承自 NSNumber。您不需要将浮点数转换为字符串,只需执行 [NSDecimalNumber numberWithFloat: slider.value]; @JeremyP:这是一个公平的观点。 【参考方案1】:

如果您需要做的只是从滑块中读取、保存值并显示它们,那么我建议处理源自缩放的、圆形的浮点滑块输入的原始整数。无论如何,滑块并不是一种精确的输入法,因此如果四舍五入与滑块头的像素位置不完全匹配,您的用户不会注意到。

我将在这里使用与您在从以真实世界数据作为输入的计算(如温度读数等)的计算中确定有效位数时相同的推理方式。如果您的输入源只有两位数的精度,那么将计算报告为四位有效数字是没有意义的。

当您想要对十进制值执行更多扩展计算但想要避免浮点错误时,需要使用 NSDecimals 和 NSDecimalNumbers。例如,我在应用程序中运行高精度计算或需要以某种方式操纵货币时使用它们。在这两者中,我坚持使用 NSDecimal for performance reasons,在需要与 Core Data 交互或需要将数值导入 NSDecimal 结构的场合使用 NSDecimalNumber。

在这种情况下,NSDecimal 似乎有点过头了,因为您实际上并没有以任何方式调整滑块值,只是将它们显示在屏幕上。如果您确实需要执行以后的操作(切成两半,运行公式等),我建议将滑块四舍五入为整数表示,从中创建一个 NSDecimal 结构,作为 NSDecimal 执行计算,然后使用NSDecimal / NSDecimalNumber 的字符串输出例程以在屏幕上显示结果。然后,您可以轻松地将计算值保存为 Core Data 中的 NSDecimalNumber 或 SQLite 或其他文件中的字符串表示形式。

另外,我不会太担心这种简单计算的性能,直到像 Instruments 这样的东西告诉你它们是热点。奇怪的是,这些使用 NSDecimal 等的计算不会。

【讨论】:

我也不认为性能会成为一个大问题 - 直到我开始考虑所有这些 NSDecimalNumber 对象。但你是对的,这对我打算做的事情来说太过分了。总而言之:从滑块中将它们四舍五入,并在整个过程中用作NSInteger。但我是存储为NSNumber 还是NSDecimalNumber @BoltClock - 除非您需要大量的数字,否则 NSNumber 应该非常适合在 Core Data 中存储整数。此外,如果您需要以前的精度级别,那么无论如何您都将使用 NSDecimal 进行计算,因此您显然会使用 NSDecimalNumber 来存储在 Core Data 中。 我已经对我的代码执行了必要的迁移/重构,我的应用现在使用整数。它们绝对比NSDecimalNumber 方便得多。非常感谢您的回答!

以上是关于我应该如何在核心数据中存储从 UISlider 读取的百分比值?的主要内容,如果未能解决你的问题,请参考以下文章

在没有 Timer 的情况下播放核心动画时如何自动更新 UISlider 的值

我应该如何存储核心数据“选定”项目?

如何从核心数据中获取最多计数的字符串值

核心图像过滤器 iOS UISlider

在swift 3中检测uislider拇指拖动的方向

如何在 cellEdit 之后强制从持久存储重新加载核心数据