使用JSONSerialization解码NSArray编码的JSON字符串失败,求原因
关于JSONSerialization编码数组后解码失败的问题分析与解决
哈哈,这个问题我之前也踩过坑!其实JSONSerialization本身完全支持顶层数组的解析,你遇到的解码失败大概率不是引擎本身的问题,而是编码/解码方法的实现细节或者后续的类型处理出了问题,咱们一步步排查:
最可能的原因:解码时强制转换为字典类型
我猜你的Decode方法里,最后可能是把解析结果直接转成NSDictionary或者[String: Any]了?比如像这样:
static func Decode(_ str: String) -> [String: Any]? { guard let data = str.data(using: .utf8) else { return nil } return try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] }
如果是这样的话,当你解码数组的JSON字符串时,解析出来的是NSArray类型,转字典自然会失败,返回nil——看起来像是解码出错,但其实解析过程是成功的,只是类型转换不对。
其他可能的原因
除了类型转换的问题,还有几个小细节要检查:
- 编码后的字符串是否被意外修改:比如编码后不小心给字符串加了换行、空格或者其他非JSON字符,导致解析时数据无效。可以打印一下
Encode得到的字符串,看看是不是标准的JSON数组格式(比如"[1,2,3,4,5]")。 - 字符编码不一致:编码时用
.utf8转成String,解码时一定要用同样的编码转回Data,如果编码和解码用了不同的字符集(比如.utf16),就会导致数据不匹配。 - 编码选项的影响:如果编码时用了
prettyPrinted选项,虽然生成的字符串带格式,但解析本身是支持的,不过要是字符串被截断或者格式损坏,也会导致解析失败。
解决方法
1. 修正Decode方法,不要强制绑定字典类型
把Decode方法改成返回Any?,让调用者自己判断返回类型,或者添加泛型支持:
class JSON { static func Encode(_ obj: Any) -> String? { guard let data = try? JSONSerialization.data(withJSONObject: obj, options: []) else { return nil } return String(data: data, encoding: .utf8) } static func Decode(_ str: String) -> Any? { guard let data = str.data(using: .utf8) else { print("字符串转Data失败") return nil } do { let result = try JSONSerialization.jsonObject(with: data, options: []) return result } catch { print("解码出错:\(error.localizedDescription)") return nil } } }
调用的时候这样处理:
let a = [1,2,3,4,5] if let encodedStr = JSON.Encode(a) { if let decodedObj = JSON.Decode(encodedStr) { switch decodedObj { case let arr as [Int]: print("解码成功,得到数组:\(arr)") case let dict as [String: Any]: print("解码成功,得到字典:\(dict)") default: print("解码得到其他类型") } } }
2. 验证编码结果的正确性
每次编码后打印一下字符串,确认是标准的JSON格式,比如数组的JSON应该是[1,2,3,4,5](不带额外的引号或者转义错误),如果格式不对,就要检查Encode方法的实现是否正确。
3. 统一字符编码
确保Encode和Decode都使用.utf8编码,避免因为字符集不一致导致数据损坏。
内容的提问来源于stack exchange,提问作者Kim Aldis
相关产品推荐
相关产品推荐

