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

无法将JSON解析为Struct对象,Swift代码报错求助

解决JSON解析为Struct的类型转换错误

我来帮你搞定这个问题!你遇到的Could not cast value of type '__NSDictionaryM' to 'NSArray'错误,核心原因是Codeforces API返回的JSON结构并不是直接的数组,而是一个包含status和result字段的外层字典,你之前直接把整个JSON对象强制转换成[userData]数组,自然会失败。另外你定义的dataResponse结构体的解码逻辑也和实际API结构不匹配,咱们一步步来修正:

第一步:修正结构体以匹配API结构

首先看Codeforces user.info接口返回的JSON格式大概是这样的:

{
  "status": "OK",
  "result": [
    {
      "handle": "abhijeet_ar",
      "avatar": "...",
      // 其他userData对应的字段
    }
  ]
}

所以我们需要调整结构体(遵循Swift命名规范首字母大写)来匹配这个结构,不需要自定义解码初始化方法,默认的Decodable实现就够用:

import Foundation

// 修正后的响应结构体,匹配API返回的字典结构
struct DataResponse: Decodable {
    let status: String
    let result: [UserData] // 对应JSON里的result数组
}

// 遵循Swift命名规范,结构体首字母大写
struct UserData: Codable {
    var avatar: String
    var city: String? // 注意:有些字段可能是可选的,建议加?避免解码失败
    var contribution: Int
    var country: String?
    var friendOfCount: Int
    var handle: String
    var lastOnlineTimeSeconds: Int
    var maxRank: String
    var maxRating: Int
    var organization: String?
    var rank: String
    var rating: Int
    var registrationTimeSeconds: Int
    var titlePhoto: String
}

// 同样修正命名
enum DataError: Error {
    case dataUnavailable
    case cannotProcessData
}

另外注意:有些用户字段可能是可选的(比如city、country如果用户没填写就会缺失),给这些字段加上?可以避免因为字段缺失导致解码失败。

第二步:修正数据请求的解码逻辑

你之前用JSONSerialization强制转换的方式完全错误,应该用JSONDecoder来解码我们修正后的DataResponse结构体,然后取出里面的result数组:

struct DataRequest {
    let requestUrl: URL
    
    init(){
        // 注意:强制解包URL在生产环境不推荐,建议加错误处理
        guard let url = URL(string: "https://codeforces.com/api/user.info?handles=abhijeet_ar") else {
            fatalError("Invalid URL")
        }
        self.requestUrl = url
    }
    
    func getData(completionHandler: @escaping(Result<[UserData], DataError>) -> Void) {
        URLSession.shared.dataTask(with: self.requestUrl) { (data,response, error) in
            guard let data = data else {
                completionHandler(.failure(.dataUnavailable))
                print("-------bye-bye--------")
                return
            }
            
            do {
                print("-------entered--------")
                // 解码DataResponse结构体
                let response = try JSONDecoder().decode(DataResponse.self, from: data)
                // 取出里面的result数组,传给回调
                completionHandler(.success(response.result))
            } catch {
                print("解码错误:\(error)") // 打印错误信息方便调试
                completionHandler(.failure(.cannotProcessData))
            }
        }.resume()
    }
}

为什么之前的代码会出错?

你之前用JSONSerialization.jsonObject(with: data)得到的是整个外层字典(包含status和result的那个对象),然后你强制把它转成[userData]数组,这就相当于把一个字典当成数组来用,系统自然会抛出类型转换错误。而我们现在用JSONDecoder解码DataResponse,就能正确解析外层字典,然后取出里面的result数组,这才是符合API结构的正确做法。

测试使用示例

你可以这样调用DataRequest来获取数据:

let request = DataRequest()
request.getData { result in
    switch result {
    case .success(let users):
        print("获取到用户数据:\(users)")
        // 处理用户数据
    case .failure(let error):
        print("请求失败:\(error)")
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 15:22:47