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

Swift JSON解码报错:Scoreboard需遵循Decodable协议问题排查

问题分析与解决方案

核心问题1:泛型参数遮蔽自定义类型

你在loadNbaScoreboardData函数里声明了泛型<Scoreboard>,这个泛型占位符会直接遮蔽你自己定义的Scoreboard结构体。编译器会把函数里的所有Scoreboard当成无约束的泛型参数,而非你写的Codable结构体——这就是为什么会出现「无法找到Scoreboard类型」和「需要遵循Decodable」的错误。

核心问题2:异步任务的返回逻辑错误

URLSession.dataTask是异步执行的,函数里的retData会在网络请求完成前就被返回,此时它还未被赋值;同时闭包里的赋值操作也无法同步影响外部变量。另外fatalError(error)的用法错误,fatalError需要传入字符串,不能直接传Error实例。

修正后的完整代码

1. Codable结构体(无需修改,确保和函数在同一作用域)

struct ResultSet: Codable {
    var name: String
    var headers: [String]
    var rowSet: [String]
}

struct Scoreboard: Codable {
    var resultSets: [ResultSet]
}

2. 修正后的请求解码函数

用闭包回调处理异步结果,去掉错误的泛型声明:

func loadNbaScoreboardData(completion: @escaping (Result<Scoreboard, Error>) -> Void) {
    let formatter = DateFormatter()
    formatter.dateFormat = "MM/dd/yyyy"
    let formattedDate = formatter.string(from: Date())
    
    guard let url = URL(string: "https://stats.nba.com/stats/scoreboard/?GameDate=\(formattedDate)&LeagueID=00&DayOffset=100") else {
        completion(.failure(NSError(domain: "InvalidURL", code: -1, userInfo: nil)))
        return
    }
    
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue("stats.nba.com", forHTTPHeaderField: "host")
    request.setValue("application/json", forHTTPHeaderField: "Accept")
    request.setValue("stats", forHTTPHeaderField: "x-nba-stats-origin")
    request.setValue("https://stats.nba.com", forHTTPHeaderField: "Referer") // 修正Referer头的错误值
    
    URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            completion(.failure(error))
            return
        }
        
        guard let data = data else {
            completion(.failure(NSError(domain: "NoData", code: -2, userInfo: nil)))
            return
        }
        
        do {
            let decodedData = try JSONDecoder().decode(Scoreboard.self, from: data)
            completion(.success(decodedData))
        } catch {
            completion(.failure(error))
        }
    }.resume()
}

调用示例

loadNbaScoreboardData { result in
    switch result {
    case .success(let scoreboard):
        print("解码成功:\(scoreboard.resultSets)")
    case .failure(let error):
        print("解码失败:\(error.localizedDescription)")
    }
}

额外说明:原代码里的Referer头值写错了,应该是完整域名https://stats.nba.com,否则可能被NBA服务器拒绝请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 21:20:33