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

Swift中如何解决NSCocoaErrorDomain Code=3840解析错误?

Swift中JSON解析遇到NSCocoaErrorDomain Code=3840 "No value."错误

问题描述

我在Swift中解析POST请求的JSON响应时,持续遇到如下错误:

Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}

相关实现代码如下:

let dict = [ "phone": phone, "firstname": "\(String(describing: firstName))", "lastname": "\(String(describing: lastName))" ] as [String: Any]
if let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: []) {
    var request = URLRequest(url: URL(string: "\(config.baseURL)employee")!)
    request.httpMethod = "POST"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = jsonData
    request.timeoutInterval = 30.0
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if error != nil {
            DispatchQueue.main.async {
                self.alertController.singleButtonAlertController("Error", (error?.localizedDescription)!, self, self.defaultAction)
                return
            }
        }
        guard let data_ = data else { return }
        do {
            let jsonObj = try JSONSerialization.jsonObject(with: data_, options: .mutableContainers) as? NSDictionary
            guard let parseJSON = jsonObj else { return }
            self.navigationItem.rightBarButtonItem = self.rightBarButton
            let meta = parseJSON["meta"] as? [String:Any]
            let status = meta!["status"] as? String
            if status == "200" {
                isEmployeeModified = true
                self.dismiss(animated: true, completion: nil)
            } else {
                let info = meta!["info"] as? String
                let message = meta!["message"] as? String
                DispatchQueue.main.async {
                    self.alertController.singleButtonAlertController(info!, message!, self, self.defaultAction)
                }
            }
        } catch let error as NSError {
            print(error)
        }
    }
    task.resume()
}

项目其他部分使用类似代码均运行正常,请求帮助解决该错误。


解决方案

这个3840错误通常意味着你尝试解析的数据不是有效的JSON格式,或者数据本身是空的。结合你的代码,我整理了几个排查和修复的步骤:

1. 先确认服务器返回的原始数据

在解析JSON之前,先把返回的data_转换成字符串打印出来,看看服务器到底给了你什么:

guard let data_ = data else { return }
// 新增这行打印,查看原始响应内容
if let responseString = String(data: data_, encoding: .utf8) {
    print("服务器原始响应:\(responseString)")
}
do {
    // 原来的解析代码...
}

如果打印出来是空字符串,或者是HTML错误页面(比如404、500的错误页面),那问题出在请求本身(比如URL错误、参数不符合要求),而不是解析代码。

2. 杜绝强制解包,避免隐性崩溃

你的代码里多处使用了!强制解包(比如meta!["status"]、info!),如果服务器返回的JSON里没有meta字段,或者meta里没有status/info/message,不仅会触发错误,还可能导致崩溃。改成可选绑定更安全:

if let meta = parseJSON["meta"] as? [String:Any],
   let status = meta["status"] as? String {
    if status == "200" {
        isEmployeeModified = true
        DispatchQueue.main.async {
            self.navigationItem.rightBarButtonItem = self.rightBarButton
            self.dismiss(animated: true, completion: nil)
        }
    } else {
        let info = meta["info"] as? String ?? "未知错误"
        let message = meta["message"] as? String ?? "请稍后重试"
        DispatchQueue.main.async {
            self.alertController.singleButtonAlertController(info, message, self, self.defaultAction)
        }
    }
} else {
    // 处理meta字段不存在的情况
    DispatchQueue.main.async {
        self.alertController.singleButtonAlertController("解析错误", "服务器返回格式异常", self, self.defaultAction)
    }
}

注意:还要把UI操作(比如修改navigationItem)放到DispatchQueue.main.async里,因为dataTask的闭包是在后台线程执行的,直接操作UI会有问题。

3. 检查请求参数的合法性

你用String(describing: firstName)处理可选值,如果firstName是nil,会生成字符串"nil",这很可能不符合服务器的参数要求。应该用空字符串替代nil:

let dict = [ 
    "phone": phone, 
    "firstname": firstName ?? "", 
    "lastname": lastName ?? "" 
] as [String: Any]

另外,确认phone的值不是nil,如果是可选类型也要做同样的处理。

4. 验证HTTP响应状态码

在解析JSON之前,先检查HTTP响应的状态码,确认请求是否成功:

if let httpResponse = response as? HTTPURLResponse {
    print("HTTP状态码:\(httpResponse.statusCode)")
    // 只有状态码在200-299之间才是成功的请求
    guard (200...299).contains(httpResponse.statusCode) else {
        DispatchQueue.main.async {
            self.alertController.singleButtonAlertController("请求失败", "状态码:\(httpResponse.statusCode)", self, self.defaultAction)
        }
        return
    }
}

如果状态码是400、404、500等,说明请求本身有问题,服务器可能没有返回预期的JSON数据。


内容的提问来源于stack exchange,提问作者Ishmael

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:45:27