使 NSDecimalNumber 可编码
Posted
技术标签:
【中文标题】使 NSDecimalNumber 可编码【英文标题】:Making NSDecimalNumber Codable 【发布时间】:2017-09-19 07:43:59 【问题描述】:是否可以扩展 NSDecimalNumber
以符合 Encodable & Decodable
协议?
【问题讨论】:
到目前为止你尝试过什么?你有什么要求?你想编码/解码什么? @LorenzoB 我检查了 Apple 的文档 developer.apple.com/documentation/foundation/… 以了解对自定义类型的编码和解码。我正在尝试解析来自服务器的响应,如果我使用 Double,我会失去精度。 【参考方案1】:无法扩展NSDecimalNumber
以符合Encodable
和Decodable
协议。 Jordan Rose 在下面的swift evolution email thread 中对此进行了解释。
如果您需要在 API 中输入 NSDecimalValue
,您可以围绕 Decimal
构建计算属性。
struct YourType: Codable
var decimalNumber: NSDecimalNumber
get return NSDecimalNumber(decimal: decimalValue)
set decimalValue = newValue.decimalValue
private var decimalValue: Decimal
顺便说一句。如果您使用NSNumberFormatter
进行解析,请注意known bug 在某些情况下会导致精度损失。
let f = NumberFormatter()
f.generatesDecimalNumbers = true
f.locale = Locale(identifier: "en_US_POSIX")
let z = f.number(from: "8.3")!
// z.decimalValue._exponent is not -1
// z.decimalValue._mantissa is not (83, 0, 0, 0, 0, 0, 0, 0)
改为以这种方式解析字符串:
NSDecimalNumber(string: "8.3", locale: Locale(identifier: "en_US_POSIX"))
【讨论】:
【参考方案2】:在swift中你应该使用Decimal类型。此类型从框中确认协议Encodable & Decodable
。
如果您在代码中输入了NSDecimalNumber
,则很容易将其转换为Decimal
let objcDecimal = NSDecimalNumber(decimal: 10)
let swiftDecimal = (objcDecimal as Decimal)
【讨论】:
【参考方案3】:使用 Swift 5.1,您可以使用属性包装器来避免编写自定义 init(from decoder: Decoder)
/ encode(to encoder: Encoder)
的样板。
@propertyWrapper
struct NumberString
private let value: String
var wrappedValue: NSDecimalNumber
init(wrappedValue: NSDecimalNumber)
self.wrappedValue = wrappedValue
value = wrappedValue.stringValue
extension NumberString: Decodable
init(from decoder: Decoder) throws
value = try String(from: decoder)
wrappedValue = NSDecimalNumber(string: value)
extension NumberString: Encodable
func encode(to encoder: Encoder) throws
var container = encoder.singleValueContainer()
try container.encode(wrappedValue.stringValue)
extension NumberString: Equatable
用法:
struct Foo: Codable
@NumberString var value: NSDecimalNumber
【讨论】:
以上是关于使 NSDecimalNumber 可编码的主要内容,如果未能解决你的问题,请参考以下文章