如何配置JSONEncoder为整数型Double添加小数点及末尾零以生成JSON?
如何让JSONEncoder编码Double类型时保留.0后缀
当然可以实现!默认的JSONEncoder会自动把整数值的Double(比如1.0)优化编码成整数形式(1),但我们可以通过自定义编码逻辑强制保留小数点后缀,让输出符合你的期望。
解决方案:自定义编码逻辑
核心思路是:通过CFNumberCreate明确创建double类型的NSNumber,让JSONEncoder识别这是一个浮点数,即使它的数值是整数,也会输出带小数点的格式。
方法1:针对单个结构体自定义编码
直接在你的NumberTest结构体中实现encode(to:)方法,手动处理number属性的编码:
import Foundation struct NumberTest: Codable { let number: Double enum CodingKeys: String, CodingKey { case number } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) // 拷贝Double值到变量(CFNumberCreate需要传入指针) var doubleValue = number // 创建明确为double类型的CFNumber,再转成NSNumber guard let cfNumber = CFNumberCreate(nil, .doubleType, &doubleValue), let nsNumber = cfNumber as NSNumber? else { throw EncodingError.invalidValue( number, EncodingError.Context( codingPath: [CodingKeys.number], debugDescription: "Failed to create CFNumber for Double value" ) ) } // 编码这个NSNumber try container.encode(nsNumber, forKey: .number) } } // 测试代码 let doubleNumber = NumberTest(number: 1.0) if let data = try? JSONEncoder().encode(doubleNumber), let jsonString = String(data: data, encoding: .utf8) { print(jsonString) // 输出: {"number":1.0} } // 测试非整数值的Double也能正常编码 let nonIntegerNumber = NumberTest(number: 1.5) if let data = try? JSONEncoder().encode(nonIntegerNumber), let jsonString = String(data: data, encoding: .utf8) { print(jsonString) // 输出: {"number":1.5} }
方法2:全局扩展Double类型(适用于所有Double属性)
如果你希望项目中所有Double类型的属性都保留小数点后缀,可以给Double添加Codable扩展,统一处理编码逻辑:
import Foundation extension Double: Codable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() var doubleValue = self guard let cfNumber = CFNumberCreate(nil, .doubleType, &doubleValue), let nsNumber = cfNumber as NSNumber? else { throw EncodingError.invalidValue( self, EncodingError.Context( codingPath: [], debugDescription: "Failed to create CFNumber for Double value" ) ) } try container.encode(nsNumber) } } // 原结构体不需要修改,直接使用即可 struct NumberTest: Codable { let number: Double enum CodingKeys: String, CodingKey { case number } } // 测试代码 let doubleNumber = NumberTest(number: 1.0) if let data = try? JSONEncoder().encode(doubleNumber), let jsonString = String(data: data, encoding: .utf8) { print(jsonString) // 输出: {"number":1.0} }
原理说明
默认情况下,当Double值是整数时,JSONEncoder会将其包装为整数类型的NSNumber,序列化时输出整数格式。而通过CFNumberCreate明确指定.doubleType创建的NSNumber,会被JSONEncoder识别为浮点数类型,因此无论数值是否为整数,都会输出带小数点的浮点数格式,完美匹配你的需求。
内容的提问来源于stack exchange,提问作者NeverThoughtIWouldPostHere
相关产品推荐
相关产品推荐

