Swift 4:自定义对象数组转JSON用于服务器参数的报错问题
我来帮你排查这个问题~你遇到的服务器错误大概率是因为生成的JSON格式不符合后端的预期,咱们一步步来梳理和解决:
问题根源分析
你用JSONSerialization来序列化[Route]数组,但你的Route结构体里有两个可选类型字段waitingMinutes和description。如果这些字段的值是nil,JSONSerialization会把它们序列化成null,而后端的接口可能不接受null值,或者要求这些字段必须存在且为非空字符串,这就导致后端在遍历数组时抛出了Invalid supplied for each()错误。另外,你代码里的强制解包data!和str!也很危险,一旦序列化失败会直接崩溃,这是需要优化的点。
解决方案
方案1:确保所有字段都符合后端要求的非空格式
如果后端要求所有字段都不能为null,你可以先处理数组里的Route对象,把nil的可选字段替换成空字符串:
// 先预处理数组,把nil字段替换为空字符串 let processedRoutes = fastForm.route.map { route in var mutableRoute = route mutableRoute.waitingMinutes = mutableRoute.waitingMinutes ?? "" mutableRoute.description = mutableRoute.description ?? "" return mutableRoute } // 再进行序列化 do { let data = try JSONSerialization.data(withJSONObject: processedRoutes, options: .prettyPrinted) if let str = String(bytes: data, encoding: .utf8) { // 用处理后的str发送请求 print(str) } } catch { print("序列化失败:\(error.localizedDescription)") }
或者直接修改Route结构体,给可选字段设置默认空字符串,从源头避免nil:
struct Route: Codable { var latitude: String var longitude: String var waitingMinutes: String = "" var description: String = "" }
方案2:改用JSONEncoder(更推荐)
既然你的Route已经实现了Codable,用专门为Codable设计的JSONEncoder会更适配,还能灵活配置序列化规则:
do { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted // 配置:如果后端不想看到null值,就关闭nil值的编码(iOS 13+支持) encoder.encodeNilValues = false let data = try encoder.encode(fastForm.route) if let str = String(bytes: data, encoding: .utf8) { // 发送请求 print(str) } } catch { print("序列化出错:\(error.localizedDescription)") }
这个方案里,encodeNilValues = false会让nil的字段直接从JSON中消失,而不是被序列化成null,这很可能就是后端需要的格式。
额外提醒
服务器返回的Invalid supplied for each()通常是后端在遍历你传递的数组时,发现某个元素的格式不符合要求(比如缺失必填字段、字段类型错误)。你可以把生成的JSON字符串打印出来,对比后端接口文档,看看是不是有字段不符合预期,这样能更快定位问题。
内容的提问来源于stack exchange,提问作者Artyom

