无法将JSON解析为Struct对象,Swift代码报错求助
我来帮你搞定这个问题!你遇到的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

