Swift解析NHL standings JSON:获取完整球队信息数组
解决NHL API完整球队数据获取问题
看起来你已经成功解析了API返回的数据,但卡在了从嵌套的Records结构中提取完整球队记录这一步。问题出在你目前只把球队名字存到了扁平数组里,但核心的TeamRecord(包含战绩、积分、排名等)还是嵌套在standingData的分区结构中,导致你在tableView里无法正确索引到对应球队的完整数据。
核心问题分析
你的standingData是[Records]类型,每个Records对应一个分区,里面包含多个TeamRecord。但你在cellForRowAt里尝试用indexPath.row直接访问standingData[indexPath.row].teamRecords[indexPath.row],这明显是错误的:
standingData的元素数量是分区数(远小于球队总数),直接用indexPath.row访问会导致数组越界- 每个分区的球队数量不同,无法用同一个索引同时定位分区和分区内的球队
解决方案:扁平化存储所有TeamRecord
我们不需要单独存球队名字数组,而是直接把所有分区的TeamRecord提取到一个扁平数组里,这样每个tableView行就能直接对应一个完整的球队记录。
修改后的代码
1. 更新ViewController的属性
把原来的standingData和standings替换成一个扁平的TeamRecord数组:
import UIKit class StandingsTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { var standingsURL: URL = URL(string: "https://statsapi.web.nhl.com/api/v1/standings")! @IBOutlet weak var tableView: UITableView! // 替换原来的两个数组,直接存储所有球队的完整记录 var allTeamRecords: [TeamRecord] = [] let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray) override func viewDidLoad() { super.viewDidLoad() loadStandings() } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 100 } // ... 其他原有方法不变 ...
2. 修改数据解析逻辑
在dataLoaded方法里,遍历所有分区的teamRecords,把它们全部添加到扁平数组中:
func dataLoaded(data:Data?,response:URLResponse?,error:Error?){ if let standingsDetailData = data{ let decoder = JSONDecoder() do { let jsondata = try decoder.decode(Initial.self, from: standingsDetailData) // 清空数组(避免重复加载) allTeamRecords.removeAll() // 遍历所有分区,把每个分区的球队记录添加到扁平数组 for record in jsondata.records ?? [] { allTeamRecords.append(contentsOf: record.teamRecords) } // 可以打印第一个球队的完整数据验证 print(allTeamRecords.first ?? "No data") DispatchQueue.main.async{ self.tableView.reloadData() self.activityIndicator.removeFromSuperview() } }catch let error{ print(error) } }else{ print(error!) } }
3. 更新TableView数据源方法
现在可以直接用扁平数组来提供数据,避免索引错误:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return allTeamRecords.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "standingsCell", for: indexPath) as! standingsCell let teamRecord = allTeamRecords[indexPath.row] // 赋值球队名称 let teamName = teamRecord.team.name cell.teamImage.image = UIImage(named: teamName) // 赋值战绩、积分等数据 cell.gamesPlayed.text = "\(teamRecord.gamesPlayed)" cell.wins.text = "\(teamRecord.leagueRecord.wins)" cell.loses.text = "\(teamRecord.leagueRecord.losses)" cell.overTime.text = teamRecord.leagueRecord.ot.map { "\($0)" } ?? "0" cell.points.text = "\(teamRecord.points)" return cell }
额外提示
- 注意
leagueRecord.ot是可选值,所以用map来安全解包,避免崩溃 - 如果你的
standingsCell还没有对应IBOutlet,记得在Storyboard里把label和代码关联起来 - 可以考虑给
TeamRecord添加自定义的description方法,方便调试时查看完整数据
内容的提问来源于stack exchange,提问作者Brent Le Comte
相关产品推荐
相关产品推荐

