为什么UITableView方法会在JSON数据解析完成前被调用并引发越界错误?
问题原因及解决方案
根因
URLSession.shared.dataTask是异步执行的逻辑,调用resume()后不会阻塞主线程等待网络请求返回,主线程会直接继续执行后续逻辑,此时UITableView会提前触发代理方法,而网络请求还未返回,news数组为空,就会触发后续报错。
现存错误点
numberOfRowsInSection硬编码返回20,和news数组的实际长度完全不匹配:网络请求未返回时news长度为0,cellForRowAt要访问数组第0~19位元素直接触发越界。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
相关产品推荐
相关产品推荐

