最近我在 Swift 中遇到了一个关于单位和测量的非常奇怪的行为,我无法理解。使用静态 UnitMass 访问器创建的单位创建测量后,我可以正确格式化它们并接收合理的输出:
let measurement = Measurement(value: 42.0, unit: UnitMass.kilograms)
measurement.formatted() // -> "42 kg" correct
当使用使用 init 及其符号创建的 UnitMass 创建测量时,我得到错误的输出
let anotherMass = UnitMass(symbol: UnitMass.kilograms.symbol)
let anotherMeasurement = Measurement(value: 42.0, unit: anotherMass)
anotherMeasurement.formatted() // -> "0 μg" wrong
使用
MeasurementFormatter
而不是访问测量中的 formatted
时,也会发生同样的情况。有趣的是:当在操场上调试它并检查输出 anotherMass 和 anotherMeasurement 似乎是有效的并产生合理的值:
完整的游乐场
import UIKit
let mass = UnitMass.kilograms
let anotherMass = UnitMass(symbol: mass.symbol)
let measurement = Measurement(value: 42.0, unit: mass)
let anotherMeasurement = Measurement(value: 42.0, unit: anotherMass)
let formatted = measurement.formatted()
let anotherFormatted = anotherMeasurement.formatted()
不幸的是,我认为我不能只使用静态 init,因为我想在 SwiftData 模型中存储一个单元,并且因为 UnitMass 不可编码,所以我只能存储符号表示。因此,在转换回单位时,我需要使用
init(symbol:)
。
您使用的
init
在 Unit
中声明。它不会知道有关 UnitMass
的任何信息,也不会看到您的符号与 UnitMass.kilograms
相同,并返回 UnitMass.kilograms
。毕竟,如果以这种方式工作,您将无法创建与现有单位具有相同符号的新单位。 Unit.init
只是创建一个带有该符号的全新单位,与任何其他单位无关。
Dimension.init(symbol:converter)
创建自定义单位。请参阅文档
定义自定义单位的最简单方法是使用
方法创建现有NSDimension
子类的新实例。init(symbol:converter:)
这大概也适用于
Unit.init(symbol:)
。
如果您想在 SwiftData 中存储单位,解决方法是存储
Data
的 Unit
表示(您可以从 NSKeyedArchiver
获取,因为 Unit
符合 NSSecureCoding
)。
或者,您也可以存储转换系数。您可以通过获得
(unit.converter as? UnitConverterLinear).coefficint
来获得此信息。然后使用 Dimension.init(symbol:converter)
重新创建您的单位,作为具有相同转换系数的自定义单位。但是,通过这种方式,您仍然会失去格式化的本地化功能。