Swift 4解析JSON时保留Double小数格式并判断原始数字类型
解决Swift中JSONSerialization解析数字类型模糊的问题
嘿,这个问题我之前踩过坑——JSONSerialization解析JSON时,会把所有数字都包装成NSNumber实例,而NSNumber本身支持双向转换(Int和Double互转),所以判断顺序一变结果就不对,确实很难直接区分JSON里的原始是整数还是小数。下面给你几个可行的解决思路:
思路1:用Codable明确指定类型(推荐)
如果你的JSON结构是固定的,优先用JSONDecoder结合自定义Codable类型,这样能直接在定义阶段就锁定数字类型,从根源上避免模糊判断:
// 假设你的JSON结构是 {"value": 1.0} struct MyModel: Codable { let value: Double // 如果原始JSON是整数1,就改成Int } do { let model = try JSONDecoder().decode(MyModel.self, from: data) // 这里model.value的类型完全匹配你定义的,完美保留原始格式意图 } catch { print("解析失败:\(error)") }
这种方式最安全,也符合Swift的类型安全原则,只要JSON结构固定就优先用它。
思路2:结合原始JSON字符串检查(原生方案)
如果必须用JSONSerialization,可以先把原始Data转成字符串,再定位到对应数字的字符串片段,通过是否包含小数点来判断原始类型:
do { // 先获取原始JSON字符串 guard let jsonString = String(data: data, encoding: .utf8) else { print("无法转成字符串") return } // 解析成Any类型 let json = try JSONSerialization.jsonObject(with: data, options: []) // 假设我们要检查key为"number"的值 if let dict = json as? [String: Any], let num = dict["number"] as? NSNumber { // 这里用正则匹配提取对应数字的字符串片段 let regexPattern = "\"number\":\\s*([0-9]+(\\.[0-9]+)?)" if let regex = try? NSRegularExpression(pattern: regexPattern), let match = regex.firstMatch(in: jsonString, range: NSRange(jsonString.startIndex..., in: jsonString)) { let numString = String(jsonString[Range(match.range(at: 1), in: jsonString)!]) if numString.contains(".") { print("原始是小数类型:\(num)") } else { print("原始是整数类型:\(num)") } } } } catch { print(error) }
这个方法有点繁琐,但完全用原生API实现,适合不能引入第三方库的场景。
思路3:用第三方JSON库(简单高效)
像SwiftyJSON这类第三方库会在解析时保留原始JSON的类型信息,能直接区分整数和小数:
import SwiftyJSON let json = JSON(data: data) if let doubleValue = json["number"].double { print("原始是小数类型:\(doubleValue)") } else if let intValue = json["number"].int { print("原始是整数类型:\(intValue)") }
SwiftyJSON内部会记录每个值的原始JSON类型,所以不用操心转换顺序的问题,用起来非常省心。
补充:为什么检查CFType没用?
因为不管JSON里是1还是1.0,JSONSerialization都会把它转成NSNumber,而NSNumber的CFType都是CFNumberType,所以通过CFType根本区分不出原始类型,这也是这个思路行不通的原因。
内容的提问来源于stack exchange,提问作者swebal
相关产品推荐
相关产品推荐

