Swift3 iOS POST数据遇NSInvalidArgumentException错误及JSON格式适配
解决Swift3 POST请求时的NSInvalidArgumentException错误(JSON顶层类型无效)
首先咱们得搞明白这个报错的根源:NSJSONSerialization只允许JSON的顶层类型是数组(Array)或者字典(Dictionary),如果你直接把单个模型对象传给它做序列化,就会触发这个Invalid top-level type的异常。而你需要的请求结构是包含datarollup和Seasonalitylist数组的字典,所以核心就是把你的数据包装成符合要求的顶层字典再做序列化。
下面分步骤给你解决:
1. 让实体类能转成JSON兼容的字典/数组
Swift3还没有Swift4才引入的Codable,所以咱们得给实体类手动加一个转字典的方法。假设你的两个实体类是这样的:
示例实体类代码
// Datarollup实体类 class DatarollupModel: NSObject { var id: String? var name: String? // 其他业务属性... // 转字典方法,把属性转成JSON支持的键值对 func toDictionary() -> [String: Any] { var dict = [String: Any]() dict["id"] = id dict["name"] = name // 其他属性依次添加进去 return dict } } // Seasonality实体类 class SeasonalityModel: NSObject { var month: String? var value: Double? // 其他业务属性... // 转字典方法 func toDictionary() -> [String: Any] { var dict = [String: Any]() dict["month"] = month dict["value"] = value // 其他属性依次添加进去 return dict } }
2. 组装符合要求的请求数据结构
把你的数据赋值完成后,包装成顶层字典——这就是服务器需要的JSON结构:
// 1. 创建并赋值datarollup模型 let datarollup = DatarollupModel() datarollup.id = "1001" datarollup.name = "Q3销售汇总" // 其他属性按需赋值... // 2. 创建并赋值Seasonalitylist数组 var seasonalityList = [SeasonalityModel]() let seasonJan = SeasonalityModel() seasonJan.month = "January" seasonJan.value = 23000.0 seasonalityList.append(seasonJan) let seasonFeb = SeasonalityModel() seasonFeb.month = "February" seasonFeb.value = 28500.0 seasonalityList.append(seasonFeb) // 可以继续添加更多季度/月度数据... // 3. 组装顶层请求字典(关键!这就是符合要求的JSON结构) let requestDict: [String: Any] = [ "datarollup": datarollup.toDictionary(), "Seasonalitylist": seasonalityList.map { $0.toDictionary() } ]
3. 正确序列化并发起POST请求
现在用这个顶层字典来序列化Data,就不会再触发异常了:
// 把字典序列化为JSON Data var jsonData: Data? do { jsonData = try JSONSerialization.data(withJSONObject: requestDict, options: []) } catch let error { print("JSON序列化失败: \(error.localizedDescription)") return } // 构建POST请求 let apiUrl = URL(string: "你的服务器API地址")! var request = URLRequest(url: apiUrl) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = jsonData // 发起请求并处理响应 let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { print("请求出错: \(error.localizedDescription)") return } // 这里处理服务器返回的响应数据 if let responseData = data { // 解析响应逻辑... } } task.resume()
关键注意事项
- 绝对不能直接把单个模型对象传给
JSONSerialization.data(withJSONObject:),必须是顶层字典或数组 - 确保所有要序列化的属性都是JSON支持的类型:
String、Int、Double、Bool、Array、Dictionary,自定义对象必须先转成字典/数组 - Swift3里
JSONSerialization的options如果不需要格式化输出,传空数组[]即可
内容的提问来源于stack exchange,提问作者user2786
相关产品推荐
相关产品推荐

