You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用NSJSONSerialization时出现JSON写入错误及方法匹配问题求助

问题分析与解决

错误原因

  1. 第一个错误:[NSJSONSerialization dataWithJSONObject:options:error:]: Invalid top-level type in JSON write
    你用了Alamofire的responseDecodable(of: M.self),这个方法已经把服务器响应的JSON数据直接解码成了M类型的自定义模型对象。而JSONSerialization.data(withJSONObject:)只接受JSON原生类型(比如字典、数组、字符串、数字等),把自定义模型传进去自然会报错,因为它不是JSON支持的顶层类型。

  2. 第二个错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:52:54