Swift iOS Codable解析JSON时如何将value格式化为3位小数
问题说明
- 接口返回JSON格式的油价数据,需要在数据模型初始化阶段完成字段格式化,要求
value字段固定保留3位小数,例如原始值"2.81"需要处理为"2.810" - 接口返回原始JSON结构如下:
[ { "name": "Diesel", "id": "1", "maj": "2022-07-06 18:28:29", "value": "2.81" }, { "name": "SP95", "id": "5", "maj": "2022-07-06 18:28:29", "value": "2.048" } ]
- 当前已定义的
Codable模型如下,曾尝试结合CustomStringConvertible实现格式化但未成功,不确定方案合理性:
struct Price: Codable { let name: String let id, maj: String? var value: String? var isCheapest: Bool? }
实现方案
CustomStringConvertible仅用于自定义实例打印、转字符串时的输出规则,不适合做解码阶段的数据清洗,不推荐用这个思路实现需求。最稳妥的方案是自定义Codable初始化方法,在解码时一次性完成字段格式化,后续使用无需重复计算。
- 先定义全局复用的数字格式化器,固定3位小数规则,同时避免区域设置导致的小数点符号异常:
private let priceFormatter: NumberFormatter = { let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.minimumFractionDigits = 3 formatter.maximumFractionDigits = 3 formatter.decimalSeparator = "." return formatter }()
- 重写
Price结构体的解码初始化方法,在解码value字段时完成格式化:
struct Price: Codable { let name: String let id, maj: String? var value: String? var isCheapest: Bool? enum CodingKeys: String, CodingKey { case name, id, maj, value, isCheapest } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 解码无需特殊处理的基础字段 name = try container.decode(String.self, forKey: .name) id = try container.decodeIfPresent(String.self, forKey: .id) maj = try container.decodeIfPresent(String.self, forKey: .maj) isCheapest = try container.decodeIfPresent(Bool.self, forKey: .isCheapest) // 格式化value字段 guard let rawValueStr = try container.decodeIfPresent(String.self, forKey: .value), let rawNumber = Double(rawValueStr), let formattedValue = priceFormatter.string(from: NSNumber(value: rawNumber)) else { value = nil return } value = formattedValue } }
- 效果验证:解码上述示例JSON后,Diesel对应的
value为"2.810",SP95对应的value保持"2.048",符合预期。如果后续需要调整小数位数,仅需修改格式化器的minimumFractionDigits、maximumFractionDigits属性即可,无需改动解码逻辑。
也可以通过扩展给
Price增加计算属性返回格式化后的value,但这种方案每次访问属性都会触发一次格式化计算,性能远不如初始化阶段一次性处理,仅适合临时、少量使用的场景。
内容的提问来源于stack exchange,提问作者jat
相关产品推荐
相关产品推荐

