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

为什么UITableView方法会在JSON数据解析完成前被调用并引发越界错误?

问题原因及解决方案

根因

URLSession.shared.dataTask是异步执行的逻辑,调用resume()后不会阻塞主线程等待网络请求返回,主线程会直接继续执行后续逻辑,此时UITableView会提前触发代理方法,而网络请求还未返回,news数组为空,就会触发后续报错。

现存错误点

  1. numberOfRowsInSection硬编码返回20,和news数组的实际长度完全不匹配:网络请求未返回时news长度为0,cellForRowAt要访问数组第0~19位元素直接触发越界。
  2. tableView.reloadData()写在了do-catch外面,无论请求是否成功、解析是否成功都会触发刷新,哪怕news数组为空也会走代理逻辑。

修复步骤

  • 把numberOfRowsInSection的返回值改为动态取news数组的长度,有多少数据渲染多少行,无数据时返回0不会触发cellForRowAt,从根源避免越界:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return news.count
}
  • 调整downloadJSON内的刷新逻辑,将刷新操作移到JSON解析成功、news数组赋值完成之后,仅在拿到有效数据后才刷新列表:
func downloadJSON() {
    guard let url = URL(string: "https://newsapi.org/v2/top-headlines?country=us&apiKey=4cf7331ecee44bef80b632fd4c1ba6b3") else { return }
    let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
        // 先判断请求无错误、data不为空再走解析逻辑
        if error == nil, let validData = data {
            do {
                let result = try JSONDecoder().decode(APIResponse.self, from: validData)
                self.news = result.articles
                // 解析成功后回到主线程刷新列表
                DispatchQueue.main.async {
                    self.newsTableView.reloadData()
                }
                print("Articles: \(result.articles.count)")
            } catch {
                print("JSON解析错误: \(error.localizedDescription)")
            }
        } else {
            print("网络请求错误: \(error?.localizedDescription ?? "未知错误")")
        }
    }.resume()
}
  • 可选优化:初始化news数组时直接赋值为空数组,避免可选类型强制解包的风险,无需额外在cellForRowAt中做越界判断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:54:00