调用NSJSONSerialization时出现JSON写入错误及方法匹配问题求助
问题分析与解决
错误原因
第一个错误:
[NSJSONSerialization dataWithJSONObject:options:error:]: Invalid top-level type in JSON write
你用了Alamofire的responseDecodable(of: M.self),这个方法已经把服务器响应的JSON数据直接解码成了M类型的自定义模型对象。而JSONSerialization.data(withJSONObject:)只接受JSON原生类型(比如字典、数组、字符串、数字等),把自定义模型传进去自然会报错,因为它不是JSON支持的顶层类型。第二个错误:
No exact matches in call to class method 'jsonObject'
你尝试调用JSONSerialization.jsonObject()时,传入的参数是已经解码后的模型对象,类型不匹配,编译器找不到对应参数的方法重载,所以报这个错。
解决方案
你的代码做了完全多余的操作:responseDecodable已经完成了解码工作,不需要再把解码后的对象转成Data,再用JSONDecoder二次解码。直接使用response.result.get()拿到的对象即可。
另外,只判断状态码200太局限,HTTP协议里200-299都属于成功状态;错误处理也应该传递具体的错误信息,而不是返回空的NSError。
修正后的代码
class BaseAPI<T: TargetType> { func fetchData<M: Decodable>(target: T, responseClass: M.Type, completion:@escaping(Result<M?, Error>) -> Void) { let method = Alamofire.HTTPMethod(rawValue: target.methods.rawValue) let headers = Alamofire.HTTPHeaders(target.headers ?? [:]) let params = buildParams(task: target.task) AF.request(target.baseUrl + target.path, method: method, parameters: params.0, encoding: params.1, headers: headers) .responseDecodable(of: M.self) { response in switch response.result { case .success(let decodedObject): // 直接使用已经解码好的对象 completion(.success(decodedObject)) case .failure(let error): // 传递具体的错误信息 completion(.failure(error)) } // 额外处理非成功状态码的情况 if let statusCode = response.response?.statusCode, !(200...299).contains(statusCode) { let statusError = NSError(domain: "APIError", code: statusCode, userInfo: [NSLocalizedDescriptionKey: "请求状态码异常"]) completion(.failure(statusError)) } } } private func buildParams(task: Task) -> ([String:Any], ParameterEncoding) { switch task { case .requestPlain: return ([:], URLEncoding.default) case .requestParameters(parameters: let parameters, encoding: let encoding): return (parameters, encoding) } } }
额外优化点
- 把
completion的错误类型从NSError改成Error,兼容更多错误类型(包括Alamofire原生错误)。 - 用
switch处理response.result比多层guard逻辑更清晰。 - 状态码判断范围扩大到200-299,符合HTTP标准规范。
内容的提问来源于stack exchange,提问作者sanalkrlk
相关产品推荐
相关产品推荐

